diff options
Diffstat (limited to 'modules')
25 files changed, 1940 insertions, 1208 deletions
diff --git a/modules/Android.mk b/modules/Android.mk index 0725d3e..13a0b5b 100644 --- a/modules/Android.mk +++ b/modules/Android.mk @@ -1,4 +1,4 @@ hardware_modules := gralloc hwcomposer audio nfc nfc-nci local_time \ - power usbaudio audio_remote_submix camera consumerir sensors vibrator \ + power usbaudio audio_remote_submix camera usbcamera consumerir sensors vibrator \ tv_input fingerprint include $(call all-named-subdir-makefiles,$(hardware_modules)) diff --git a/modules/camera/CameraHAL.cpp b/modules/camera/CameraHAL.cpp index 6f64a0d..06f308f 100644 --- a/modules/camera/CameraHAL.cpp +++ b/modules/camera/CameraHAL.cpp @@ -185,6 +185,7 @@ camera_module_t HAL_MODULE_INFO_SYM __attribute__ ((visibility("default"))) = { set_callbacks : set_callbacks, get_vendor_tag_ops : get_vendor_tag_ops, open_legacy : NULL, + set_torch_mode : NULL, reserved : {0}, }; } // extern "C" diff --git a/modules/usbaudio/Android.mk b/modules/usbaudio/Android.mk index ec8a8c0..9df1e79 100644 --- a/modules/usbaudio/Android.mk +++ b/modules/usbaudio/Android.mk @@ -19,15 +19,12 @@ include $(CLEAR_VARS) LOCAL_MODULE := audio.usb.default LOCAL_MODULE_RELATIVE_PATH := hw LOCAL_SRC_FILES := \ - audio_hw.c \ - alsa_device_profile.c \ - alsa_device_proxy.c \ - logging.c \ - format.c + audio_hal.c LOCAL_C_INCLUDES += \ external/tinyalsa/include \ - $(call include-path-for, audio-utils) -LOCAL_SHARED_LIBRARIES := liblog libcutils libtinyalsa libaudioutils + $(call include-path-for, audio-utils) \ + $(call include-path-for, alsa-utils) +LOCAL_SHARED_LIBRARIES := liblog libcutils libtinyalsa libaudioutils libalsautils LOCAL_MODULE_TAGS := optional LOCAL_CFLAGS := -Wno-unused-parameter diff --git a/modules/usbaudio/alsa_device_profile.c b/modules/usbaudio/alsa_device_profile.c deleted file mode 100644 index 8e84471..0000000 --- a/modules/usbaudio/alsa_device_profile.c +++ /dev/null @@ -1,497 +0,0 @@ -/* - * Copyright (C) 2014 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 "alsa_device_profile" -/*#define LOG_NDEBUG 0*/ -/*#define LOG_PCM_PARAMS 0*/ - -#include <errno.h> -#include <inttypes.h> -#include <stdint.h> -#include <stdlib.h> - -#include <log/log.h> - -#include "alsa_device_profile.h" -#include "format.h" -#include "logging.h" - -#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) - -/*TODO - Evaluate if this value should/can be retrieved from a device-specific property */ -#define BUFF_DURATION_MS 5 - -#define DEFAULT_PERIOD_SIZE 1024 - -static const char * const format_string_map[] = { - "AUDIO_FORMAT_PCM_16_BIT", /* "PCM_FORMAT_S16_LE", */ - "AUDIO_FORMAT_PCM_32_BIT", /* "PCM_FORMAT_S32_LE", */ - "AUDIO_FORMAT_PCM_8_BIT", /* "PCM_FORMAT_S8", */ - "AUDIO_FORMAT_PCM_8_24_BIT", /* "PCM_FORMAT_S24_LE", */ - "AUDIO_FORMAT_PCM_24_BIT_PACKED"/* "PCM_FORMAT_S24_3LE" */ -}; - -static const unsigned const format_byte_size_map[] = { - 2, /* PCM_FORMAT_S16_LE */ - 4, /* PCM_FORMAT_S32_LE */ - 1, /* PCM_FORMAT_S8 */ - 4, /* PCM_FORMAT_S24_LE */ - 3, /* PCM_FORMAT_S24_3LE */ -}; - -extern int8_t const pcm_format_value_map[50]; - -/* sort these highest -> lowest (to default to best quality) */ -static const unsigned std_sample_rates[] = - {48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000}; - -static void profile_reset(alsa_device_profile* profile) -{ - profile->card = profile->device = -1; - - /* Fill the attribute arrays with invalid values */ - size_t index; - for (index = 0; index < ARRAY_SIZE(profile->formats); index++) { - profile->formats[index] = PCM_FORMAT_INVALID; - } - - for (index = 0; index < ARRAY_SIZE(profile->sample_rates); index++) { - profile->sample_rates[index] = 0; - } - - for (index = 0; index < ARRAY_SIZE(profile->channel_counts); index++) { - profile->channel_counts[index] = 0; - } - - profile->min_period_size = profile->max_period_size = 0; - profile->min_channel_count = profile->max_channel_count = DEFAULT_CHANNEL_COUNT; - - profile->is_valid = false; -} - -void profile_init(alsa_device_profile* profile, int direction) -{ - profile->direction = direction; - profile_reset(profile); -} - -bool profile_is_initialized(alsa_device_profile* profile) -{ - return profile->card >= 0 && profile->device >= 0; -} - -bool profile_is_valid(alsa_device_profile* profile) { - return profile->is_valid; -} - -bool profile_is_cached_for(alsa_device_profile* profile, int card, int device) { - return card == profile->card && device == profile->device; -} - -void profile_decache(alsa_device_profile* profile) { - profile_reset(profile); -} - -/* - * Returns the supplied value rounded up to the next even multiple of 16 - */ -static unsigned int round_to_16_mult(unsigned int size) -{ - return (size + 15) & ~15; // 0xFFFFFFF0; -} - -/* - * Returns the system defined minimum period size based on the supplied sample rate. - */ -unsigned profile_calc_min_period_size(alsa_device_profile* profile, unsigned sample_rate) -{ - ALOGV("profile_calc_min_period_size(%p, rate:%d)", profile, sample_rate); - if (profile == NULL) { - return DEFAULT_PERIOD_SIZE; - } else { - unsigned num_sample_frames = (sample_rate * BUFF_DURATION_MS) / 1000; - if (num_sample_frames < profile->min_period_size) { - num_sample_frames = profile->min_period_size; - } - return round_to_16_mult(num_sample_frames) * 2; - } -} - -unsigned int profile_get_period_size(alsa_device_profile* profile, unsigned sample_rate) -{ - // return profile->default_config.period_size; - unsigned int period_size = profile_calc_min_period_size(profile, sample_rate); - ALOGV("profile_get_period_size(rate:%d) = %d", sample_rate, period_size); - return period_size; -} - -/* - * Sample Rate - */ -unsigned profile_get_default_sample_rate(alsa_device_profile* profile) -{ - /* - * TODO this won't be right in general. we should store a preferred rate as we are scanning. - * But right now it will return the highest rate, which may be correct. - */ - return profile_is_valid(profile) ? profile->sample_rates[0] : DEFAULT_SAMPLE_RATE; -} - -bool profile_is_sample_rate_valid(alsa_device_profile* profile, unsigned rate) -{ - if (profile_is_valid(profile)) { - size_t index; - for (index = 0; profile->sample_rates[index] != 0; index++) { - if (profile->sample_rates[index] == rate) { - return true; - } - } - - return false; - } else { - return rate == DEFAULT_SAMPLE_RATE; - } -} - -/* - * Format - */ -enum pcm_format profile_get_default_format(alsa_device_profile* profile) -{ - /* - * TODO this won't be right in general. we should store a preferred format as we are scanning. - */ - return profile_is_valid(profile) ? profile->formats[0] : DEFAULT_SAMPLE_FORMAT; -} - -bool profile_is_format_valid(alsa_device_profile* profile, enum pcm_format fmt) { - if (profile_is_valid(profile)) { - size_t index; - for (index = 0; profile->formats[index] != PCM_FORMAT_INVALID; index++) { - if (profile->formats[index] == fmt) { - return true; - } - } - - return false; - } else { - return fmt == DEFAULT_SAMPLE_FORMAT; - } -} - -/* - * Channels - */ -unsigned profile_get_default_channel_count(alsa_device_profile* profile) -{ - return profile_is_valid(profile) ? profile->channel_counts[0] : DEFAULT_CHANNEL_COUNT; -} - -bool profile_is_channel_count_valid(alsa_device_profile* profile, unsigned count) -{ - if (profile_is_initialized(profile)) { - return count >= profile->min_channel_count && count <= profile->max_channel_count; - } else { - return count == DEFAULT_CHANNEL_COUNT; - } -} - -static bool profile_test_sample_rate(alsa_device_profile* profile, unsigned rate) -{ - struct pcm_config config = profile->default_config; - config.rate = rate; - - bool works = false; /* let's be pessimistic */ - struct pcm * pcm = pcm_open(profile->card, profile->device, - profile->direction, &config); - - if (pcm != NULL) { - works = pcm_is_ready(pcm); - pcm_close(pcm); - } - - return works; -} - -static unsigned profile_enum_sample_rates(alsa_device_profile* profile, unsigned min, unsigned max) -{ - unsigned num_entries = 0; - unsigned index; - - for (index = 0; index < ARRAY_SIZE(std_sample_rates) && - num_entries < ARRAY_SIZE(profile->sample_rates) - 1; - index++) { - if (std_sample_rates[index] >= min && std_sample_rates[index] <= max - && profile_test_sample_rate(profile, std_sample_rates[index])) { - profile->sample_rates[num_entries++] = std_sample_rates[index]; - } - } - - return num_entries; /* return # of supported rates */ -} - -static unsigned profile_enum_sample_formats(alsa_device_profile* profile, struct pcm_mask * mask) -{ - const int num_slots = ARRAY_SIZE(mask->bits); - const int bits_per_slot = sizeof(mask->bits[0]) * 8; - - const int table_size = ARRAY_SIZE(pcm_format_value_map); - - int slot_index, bit_index, table_index; - table_index = 0; - int num_written = 0; - for (slot_index = 0; slot_index < num_slots && table_index < table_size; - slot_index++) { - unsigned bit_mask = 1; - for (bit_index = 0; - bit_index < bits_per_slot && table_index < table_size; - bit_index++) { - if ((mask->bits[slot_index] & bit_mask) != 0) { - enum pcm_format format = pcm_format_value_map[table_index]; - /* Never return invalid (unrecognized) or 8-bit */ - if (format != PCM_FORMAT_INVALID && format != PCM_FORMAT_S8) { - profile->formats[num_written++] = format; - if (num_written == ARRAY_SIZE(profile->formats) - 1) { - /* leave at least one PCM_FORMAT_INVALID at the end */ - return num_written; - } - } - } - bit_mask <<= 1; - table_index++; - } - } - - return num_written; -} - -static unsigned profile_enum_channel_counts(alsa_device_profile* profile, unsigned min, unsigned max) -{ - static const unsigned std_channel_counts[] = {8, 4, 2, 1}; - - unsigned num_counts = 0; - unsigned index; - /* TODO write a profile_test_channel_count() */ - /* Ensure there is at least one invalid channel count to terminate the channel counts array */ - for (index = 0; index < ARRAY_SIZE(std_channel_counts) && - num_counts < ARRAY_SIZE(profile->channel_counts) - 1; - index++) { - /* TODO Do we want a channel counts test? */ - if (std_channel_counts[index] >= min && std_channel_counts[index] <= max /* && - profile_test_channel_count(profile, channel_counts[index])*/) { - profile->channel_counts[num_counts++] = std_channel_counts[index]; - } - } - - return num_counts; /* return # of supported counts */ -} - -/* - * Reads and decodes configuration info from the specified ALSA card/device. - */ -static int read_alsa_device_config(alsa_device_profile * profile, struct pcm_config * config) -{ - ALOGV("usb:audio_hw - read_alsa_device_config(c:%d d:%d t:0x%X)", - profile->card, profile->device, profile->direction); - - if (profile->card < 0 || profile->device < 0) { - return -EINVAL; - } - - struct pcm_params * alsa_hw_params = - pcm_params_get(profile->card, profile->device, profile->direction); - if (alsa_hw_params == NULL) { - return -EINVAL; - } - - profile->min_period_size = pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIOD_SIZE); - profile->max_period_size = pcm_params_get_max(alsa_hw_params, PCM_PARAM_PERIOD_SIZE); - - profile->min_channel_count = pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS); - profile->max_channel_count = pcm_params_get_max(alsa_hw_params, PCM_PARAM_CHANNELS); - - int ret = 0; - - /* - * This Logging will be useful when testing new USB devices. - */ -#ifdef LOG_PCM_PARAMS - log_pcm_params(alsa_hw_params); -#endif - - config->channels = pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS); - config->rate = pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE); - config->period_size = profile_calc_min_period_size(profile, config->rate); - config->period_count = pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIODS); - config->format = get_pcm_format_for_mask(pcm_params_get_mask(alsa_hw_params, PCM_PARAM_FORMAT)); -#ifdef LOG_PCM_PARAMS - log_pcm_config(config, "read_alsa_device_config"); -#endif - if (config->format == PCM_FORMAT_INVALID) { - ret = -EINVAL; - } - - pcm_params_free(alsa_hw_params); - - return ret; -} - -bool profile_read_device_info(alsa_device_profile* profile) -{ - if (!profile_is_initialized(profile)) { - return false; - } - - /* let's get some defaults */ - read_alsa_device_config(profile, &profile->default_config); - ALOGV("default_config chans:%d rate:%d format:%d count:%d size:%d", - profile->default_config.channels, profile->default_config.rate, - profile->default_config.format, profile->default_config.period_count, - profile->default_config.period_size); - - struct pcm_params * alsa_hw_params = pcm_params_get(profile->card, - profile->device, - profile->direction); - if (alsa_hw_params == NULL) { - return false; - } - - /* Formats */ - struct pcm_mask * format_mask = pcm_params_get_mask(alsa_hw_params, PCM_PARAM_FORMAT); - profile_enum_sample_formats(profile, format_mask); - - /* Channels */ - profile_enum_channel_counts( - profile, pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS), - pcm_params_get_max(alsa_hw_params, PCM_PARAM_CHANNELS)); - - /* Sample Rates */ - profile_enum_sample_rates( - profile, pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE), - pcm_params_get_max(alsa_hw_params, PCM_PARAM_RATE)); - - profile->is_valid = true; - - return true; -} - -char * profile_get_sample_rate_strs(alsa_device_profile* profile) -{ - char buffer[128]; - buffer[0] = '\0'; - int buffSize = ARRAY_SIZE(buffer); - - char numBuffer[32]; - - int numEntries = 0; - unsigned index; - for (index = 0; profile->sample_rates[index] != 0; index++) { - if (numEntries++ != 0) { - strncat(buffer, "|", buffSize); - } - snprintf(numBuffer, sizeof(numBuffer), "%u", profile->sample_rates[index]); - strncat(buffer, numBuffer, buffSize); - } - - return strdup(buffer); -} - -char * profile_get_format_strs(alsa_device_profile* profile) -{ - /* TODO remove this hack when we have support for input in non PCM16 formats */ - if (profile->direction == PCM_IN) { - return strdup("AUDIO_FORMAT_PCM_16_BIT"); - } - - char buffer[128]; - buffer[0] = '\0'; - int buffSize = ARRAY_SIZE(buffer); - - int numEntries = 0; - unsigned index = 0; - for (index = 0; profile->formats[index] != PCM_FORMAT_INVALID; index++) { - if (numEntries++ != 0) { - strncat(buffer, "|", buffSize); - } - strncat(buffer, format_string_map[profile->formats[index]], buffSize); - } - - return strdup(buffer); -} - -char * profile_get_channel_count_strs(alsa_device_profile* profile) -{ - static const char * const out_chans_strs[] = { - /* 0 */"AUDIO_CHANNEL_NONE", /* will never be taken as this is a terminator */ - /* 1 */"AUDIO_CHANNEL_OUT_MONO", - /* 2 */"AUDIO_CHANNEL_OUT_STEREO", - /* 3 */ /* "AUDIO_CHANNEL_OUT_STEREO|AUDIO_CHANNEL_OUT_FRONT_CENTER" */ NULL, - /* 4 */"AUDIO_CHANNEL_OUT_QUAD", - /* 5 */ /* "AUDIO_CHANNEL_OUT_QUAD|AUDIO_CHANNEL_OUT_FRONT_CENTER" */ NULL, - /* 6 */"AUDIO_CHANNEL_OUT_5POINT1", - /* 7 */ /* "AUDIO_CHANNEL_OUT_5POINT1|AUDIO_CHANNEL_OUT_BACK_CENTER" */ NULL, - /* 8 */"AUDIO_CHANNEL_OUT_7POINT1", - /* channel counts greater than this not considered */ - }; - - static const char * const in_chans_strs[] = { - /* 0 */"AUDIO_CHANNEL_NONE", /* will never be taken as this is a terminator */ - /* 1 */"AUDIO_CHANNEL_IN_MONO", - /* 2 */"AUDIO_CHANNEL_IN_STEREO", - /* channel counts greater than this not considered */ - }; - - const bool isOutProfile = profile->direction == PCM_OUT; - - const char * const * const names_array = isOutProfile ? out_chans_strs : in_chans_strs; - const size_t names_size = isOutProfile ? ARRAY_SIZE(out_chans_strs) - : ARRAY_SIZE(in_chans_strs); - - char buffer[256]; /* caution, may need to be expanded */ - buffer[0] = '\0'; - const int buffer_size = ARRAY_SIZE(buffer); - int num_entries = 0; - /* We currently support MONO and STEREO, and always report STEREO but some (many) - * USB Audio Devices may only announce support for MONO (a headset mic for example), or - * The total number of output channels. SO, if the device itself doesn't explicitly - * support STEREO, append to the channel config strings we are generating. - */ - bool stereo_present = false; - unsigned index; - unsigned channel_count; - - for (index = 0; (channel_count = profile->channel_counts[index]) != 0; index++) { - stereo_present = stereo_present || channel_count == 2; - if (channel_count < names_size && names_array[channel_count] != NULL) { - if (num_entries++ != 0) { - strncat(buffer, "|", buffer_size); - } - strncat(buffer, names_array[channel_count], buffer_size); - } - } - - /* emulated modes: - * always expose stereo as we can emulate it for PCM_OUT - */ - if (!stereo_present) { - if (num_entries++ != 0) { - strncat(buffer, "|", buffer_size); - } - strncat(buffer, names_array[2], buffer_size); /* stereo */ - } - - return strdup(buffer); -} diff --git a/modules/usbaudio/alsa_device_profile.h b/modules/usbaudio/alsa_device_profile.h deleted file mode 100644 index 2c0da39..0000000 --- a/modules/usbaudio/alsa_device_profile.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2014 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. - */ - -#ifndef ANDROID_HARDWARE_LIBHARDWARE_MODULES_USBAUDIO_ALSA_DEVICE_PROFILE_H -#define ANDROID_HARDWARE_LIBHARDWARE_MODULES_USBAUDIO_ALSA_DEVICE_PROFILE_H - -#include <stdbool.h> - -#include <tinyalsa/asoundlib.h> - -#define MAX_PROFILE_FORMATS 6 /* We long support the 5 standard formats defined - * in asound.h, so we just need this to be 1 more - * than that */ -#define MAX_PROFILE_SAMPLE_RATES 10 /* this number needs to be 1 more than the number of - * standard formats in std_sample_rates[] - * (in alsa_device_profile.c) */ -#define MAX_PROFILE_CHANNEL_COUNTS 5 /* this number need to be 1 more than the number of - * standard channel formats in std_channel_counts[] - * (in alsa_device_profile.c) */ - -#define DEFAULT_SAMPLE_RATE 44100 -#define DEFAULT_SAMPLE_FORMAT PCM_FORMAT_S16_LE -#define DEFAULT_CHANNEL_COUNT 2 - -typedef struct { - int card; - int device; - int direction; /* PCM_OUT or PCM_IN */ - - enum pcm_format formats[MAX_PROFILE_FORMATS]; - - unsigned sample_rates[MAX_PROFILE_SAMPLE_RATES]; - - unsigned channel_counts[MAX_PROFILE_CHANNEL_COUNTS]; - - bool is_valid; - - /* read from the hardware device */ - struct pcm_config default_config; - - unsigned min_period_size; - unsigned max_period_size; - - unsigned min_channel_count; - unsigned max_channel_count; -} alsa_device_profile; - -void profile_init(alsa_device_profile* profile, int direction); -bool profile_is_initialized(alsa_device_profile* profile); -bool profile_is_valid(alsa_device_profile* profile); -bool profile_is_cached_for(alsa_device_profile* profile, int card, int device); -void profile_decache(alsa_device_profile* profile); - -bool profile_read_device_info(alsa_device_profile* profile); - -/* Audio Config Strings Methods */ -char * profile_get_sample_rate_strs(alsa_device_profile* profile); -char * profile_get_format_strs(alsa_device_profile* profile); -char * profile_get_channel_count_strs(alsa_device_profile* profile); - -/* Sample Rate Methods */ -unsigned profile_get_default_sample_rate(alsa_device_profile* profile); -bool profile_is_sample_rate_valid(alsa_device_profile* profile, unsigned rate); - -/* Format Methods */ -enum pcm_format profile_get_default_format(alsa_device_profile* profile); -bool profile_is_format_valid(alsa_device_profile* profile, enum pcm_format fmt); - -/* Channel Methods */ -unsigned profile_get_default_channel_count(alsa_device_profile* profile); -bool profile_is_channel_count_valid(alsa_device_profile* profile, unsigned count); - -/* Utility */ -unsigned profile_calc_min_period_size(alsa_device_profile* profile, unsigned sample_rate); -unsigned int profile_get_period_size(alsa_device_profile* profile, unsigned sample_rate); - -#endif /* ANDROID_HARDWARE_LIBHARDWARE_MODULES_USBAUDIO_ALSA_DEVICE_PROFILE_H */ diff --git a/modules/usbaudio/alsa_device_proxy.c b/modules/usbaudio/alsa_device_proxy.c deleted file mode 100644 index 676f288..0000000 --- a/modules/usbaudio/alsa_device_proxy.c +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (C) 2014 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 "alsa_device_proxy" -/*#define LOG_NDEBUG 0*/ -/*#define LOG_PCM_PARAMS 0*/ - -#include <log/log.h> - -#include <errno.h> - -#include "alsa_device_proxy.h" - -#include "logging.h" - -#define DEFAULT_PERIOD_SIZE 1024 -#define DEFAULT_PERIOD_COUNT 2 - -void proxy_prepare(alsa_device_proxy * proxy, alsa_device_profile* profile, - struct pcm_config * config) -{ - ALOGV("proxy_prepare()"); - - proxy->profile = profile; - -#ifdef LOG_PCM_PARAMS - log_pcm_config(config, "proxy_setup()"); -#endif - - proxy->alsa_config.format = - config->format != PCM_FORMAT_INVALID && profile_is_format_valid(profile, config->format) - ? config->format : profile->default_config.format; - proxy->alsa_config.rate = - config->rate != 0 && profile_is_sample_rate_valid(profile, config->rate) - ? config->rate : profile->default_config.rate; - proxy->alsa_config.channels = - config->channels != 0 && profile_is_channel_count_valid(profile, config->channels) - ? config->channels : profile->default_config.channels; - - proxy->alsa_config.period_count = profile->default_config.period_count; - proxy->alsa_config.period_size = - profile_get_period_size(proxy->profile, proxy->alsa_config.rate); - - // Hack for USB accessory audio. - // Here we set the correct value for period_count if tinyalsa fails to get it from the - // f_audio_source driver. - if (proxy->alsa_config.period_count == 0) { - proxy->alsa_config.period_count = 4; - } - - proxy->pcm = NULL; -} - -int proxy_open(alsa_device_proxy * proxy) -{ - alsa_device_profile* profile = proxy->profile; - ALOGV("proxy_open(card:%d device:%d %s)", profile->card, profile->device, - profile->direction == PCM_OUT ? "PCM_OUT" : "PCM_IN"); - - proxy->pcm = pcm_open(profile->card, profile->device, profile->direction, &proxy->alsa_config); - if (proxy->pcm == NULL) { - return -ENOMEM; - } - - if (!pcm_is_ready(proxy->pcm)) { - ALOGE("[%s] proxy_open() pcm_open() failed: %s", LOG_TAG, pcm_get_error(proxy->pcm)); -#ifdef LOG_PCM_PARAMS - log_pcm_config(&proxy->alsa_config, "config"); -#endif - pcm_close(proxy->pcm); - proxy->pcm = NULL; - return -ENOMEM; - } - - return 0; -} - -void proxy_close(alsa_device_proxy * proxy) -{ - ALOGV("proxy_close() [pcm:%p]", proxy->pcm); - - if (proxy->pcm != NULL) { - pcm_close(proxy->pcm); - proxy->pcm = NULL; - } -} - -/* - * Sample Rate - */ -unsigned proxy_get_sample_rate(const alsa_device_proxy * proxy) -{ - return proxy->alsa_config.rate; -} - -/* - * Format - */ -enum pcm_format proxy_get_format(const alsa_device_proxy * proxy) -{ - return proxy->alsa_config.format; -} - -/* - * Channel Count - */ -unsigned proxy_get_channel_count(const alsa_device_proxy * proxy) -{ - return proxy->alsa_config.channels; -} - -/* - * Other - */ -unsigned int proxy_get_period_size(const alsa_device_proxy * proxy) -{ - return proxy->alsa_config.period_size; -} - -unsigned int proxy_get_period_count(const alsa_device_proxy * proxy) -{ - return proxy->alsa_config.period_count; -} - -unsigned proxy_get_latency(const alsa_device_proxy * proxy) -{ - return (proxy_get_period_size(proxy) * proxy_get_period_count(proxy) * 1000) - / proxy_get_sample_rate(proxy); -} - -/* - * I/O - */ -int proxy_write(const alsa_device_proxy * proxy, const void *data, unsigned int count) -{ - return pcm_write(proxy->pcm, data, count); -} - -int proxy_read(const alsa_device_proxy * proxy, void *data, unsigned int count) -{ - return pcm_read(proxy->pcm, data, count); -} diff --git a/modules/usbaudio/alsa_device_proxy.h b/modules/usbaudio/alsa_device_proxy.h deleted file mode 100644 index f090c56..0000000 --- a/modules/usbaudio/alsa_device_proxy.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2014 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. - */ - -#ifndef ANDROID_HARDWARE_LIBHARDWARE_MODULES_USBAUDIO_ALSA_DEVICE_PROXY_H -#define ANDROID_HARDWARE_LIBHARDWARE_MODULES_USBAUDIO_ALSA_DEVICE_PROXY_H - -#include <tinyalsa/asoundlib.h> - -#include "alsa_device_profile.h" - -typedef struct { - alsa_device_profile* profile; - - struct pcm_config alsa_config; - - struct pcm * pcm; -} alsa_device_proxy; - -void proxy_prepare(alsa_device_proxy * proxy, alsa_device_profile * profile, - struct pcm_config * config); - -unsigned proxy_get_sample_rate(const alsa_device_proxy * proxy); -enum pcm_format proxy_get_format(const alsa_device_proxy * proxy); -unsigned proxy_get_channel_count(const alsa_device_proxy * proxy); - -unsigned int proxy_get_period_size(const alsa_device_proxy * proxy); - -unsigned proxy_get_latency(const alsa_device_proxy * proxy); - -int proxy_open(alsa_device_proxy * proxy); -void proxy_close(alsa_device_proxy * proxy); - -int proxy_write(const alsa_device_proxy * proxy, const void *data, unsigned int count); -int proxy_read(const alsa_device_proxy * proxy, void *data, unsigned int count); - -#endif /* ANDROID_HARDWARE_LIBHARDWARE_MODULES_USBAUDIO_ALSA_DEVICE_PROXY_H */ diff --git a/modules/usbaudio/audio_hw.c b/modules/usbaudio/audio_hal.c index ad01833..2814e37 100644 --- a/modules/usbaudio/audio_hw.c +++ b/modules/usbaudio/audio_hal.c @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_TAG "usb_audio_hw" +#define LOG_TAG "modules.usbaudio.audio_hal" /*#define LOG_NDEBUG 0*/ #include <errno.h> @@ -51,7 +51,7 @@ static const unsigned k_force_channels = 0; #include "alsa_device_profile.h" #include "alsa_device_proxy.h" -#include "logging.h" +#include "alsa_logging.h" #define DEFAULT_INPUT_BUFFER_SIZE_MS 20 @@ -184,10 +184,40 @@ static size_t convert_32_to_16(const int32_t * in_buff, size_t num_in_samples, s return num_in_samples * 2; } -static char * device_get_parameters(alsa_device_profile * profile, const char * keys) +/* + * Extract the card and device numbers from the supplied key/value pairs. + * kvpairs A null-terminated string containing the key/value pairs or card and device. + * i.e. "card=1;device=42" + * card A pointer to a variable to receive the parsed-out card number. + * device A pointer to a variable to receive the parsed-out device number. + * NOTE: The variables pointed to by card and device return -1 (undefined) if the + * associated key/value pair is not found in the provided string. + */ +static void parse_card_device_params(const char *kvpairs, int *card, int *device) { - ALOGV("usb:audio_hw::device_get_parameters() keys:%s", keys); + struct str_parms * parms = str_parms_create_str(kvpairs); + char value[32]; + int param_val; + // initialize to "undefined" state. + *card = -1; + *device = -1; + + param_val = str_parms_get_str(parms, "card", value, sizeof(value)); + if (param_val >= 0) { + *card = atoi(value); + } + + param_val = str_parms_get_str(parms, "device", value, sizeof(value)); + if (param_val >= 0) { + *device = atoi(value); + } + + str_parms_destroy(parms); +} + +static char * device_get_parameters(alsa_device_profile * profile, const char * keys) +{ if (profile->card < 0 || profile->device < 0) { return strdup(""); } @@ -311,24 +341,15 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) struct stream_out *out = (struct stream_out *)stream; - char value[32]; - int param_val; int routing = 0; int ret_value = 0; int card = -1; int device = -1; - struct str_parms * parms = str_parms_create_str(kvpairs); pthread_mutex_lock(&out->dev->lock); pthread_mutex_lock(&out->lock); - param_val = str_parms_get_str(parms, "card", value, sizeof(value)); - if (param_val >= 0) - card = atoi(value); - - param_val = str_parms_get_str(parms, "device", value, sizeof(value)); - if (param_val >= 0) - device = atoi(value); + parse_card_device_params(kvpairs, &card, &device); if (card >= 0 && device >= 0 && !profile_is_cached_for(out->profile, card, device)) { /* cannot read pcm device info if playback is active */ @@ -349,7 +370,6 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) pthread_mutex_unlock(&out->lock); pthread_mutex_unlock(&out->dev->lock); - str_parms_destroy(parms); return ret_value; } @@ -480,10 +500,11 @@ static int adev_open_output_stream(struct audio_hw_device *dev, audio_output_flags_t flags, struct audio_config *config, struct audio_stream_out **stream_out, - const char *address __unused) + const char *address /*__unused*/) { - ALOGV("usb:audio_hw::out adev_open_output_stream() handle:0x%X, device:0x%X, flags:0x%X", - handle, devices, flags); + ALOGV("usb:audio_hw::out adev_open_output_stream()" + "handle:0x%X, device:0x%X, flags:0x%X, addr:%s", + handle, devices, flags, address); struct audio_device *adev = (struct audio_device *)dev; @@ -514,13 +535,20 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->stream.get_next_write_timestamp = out_get_next_write_timestamp; out->dev = adev; - + pthread_mutex_lock(&adev->lock); out->profile = &adev->out_profile; // 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->profile->card), &(out->profile->device)); + + profile_read_device_info(out->profile); + + pthread_mutex_unlock(&adev->lock); + int ret = 0; /* Rate */ @@ -585,8 +613,9 @@ err_open: static void adev_close_output_stream(struct audio_hw_device *dev, struct audio_stream_out *stream) { - ALOGV("usb:audio_hw::out adev_close_output_stream()"); struct stream_out *out = (struct stream_out *)stream; + ALOGV("usb:audio_hw::out adev_close_output_stream(c:%d d:%d)", + out->profile->card, out->profile->device); /* Close the pcm device */ out_standby(&stream->common); @@ -691,19 +720,10 @@ static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) int card = -1; int device = -1; - struct str_parms * parms = str_parms_create_str(kvpairs); - pthread_mutex_lock(&in->dev->lock); pthread_mutex_lock(&in->lock); - /* Device Connection Message ("card=1,device=0") */ - param_val = str_parms_get_str(parms, "card", value, sizeof(value)); - if (param_val >= 0) - card = atoi(value); - - param_val = str_parms_get_str(parms, "device", value, sizeof(value)); - if (param_val >= 0) - device = atoi(value); + parse_card_device_params(kvpairs, &card, &device); if (card >= 0 && device >= 0 && !profile_is_cached_for(in->profile, card, device)) { /* cannot read pcm device info if playback is active */ @@ -725,8 +745,6 @@ static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) pthread_mutex_unlock(&in->lock); pthread_mutex_unlock(&in->dev->lock); - str_parms_destroy(parms); - return ret_value; } @@ -890,7 +908,7 @@ static int adev_open_input_stream(struct audio_hw_device *dev, struct audio_config *config, struct audio_stream_in **stream_in, audio_input_flags_t flags __unused, - const char *address __unused, + const char *address /*__unused*/, audio_source_t source __unused) { ALOGV("usb: in adev_open_input_stream() rate:%" PRIu32 ", chanMask:0x%" PRIX32 ", fmt:%" PRIu8, @@ -921,12 +939,19 @@ static int adev_open_input_stream(struct audio_hw_device *dev, in->stream.get_input_frames_lost = in_get_input_frames_lost; in->dev = (struct audio_device *)dev; + pthread_mutex_lock(&in->dev->lock); in->profile = &in->dev->in_profile; struct pcm_config proxy_config; memset(&proxy_config, 0, sizeof(proxy_config)); + /* Pull out the card/device pair */ + parse_card_device_params(address, &(in->profile->card), &(in->profile->device)); + + profile_read_device_info(in->profile); + pthread_mutex_unlock(&in->dev->lock); + /* Rate */ if (config->sample_rate == 0) { proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(in->profile); diff --git a/modules/usbaudio/format.c b/modules/usbaudio/format.c deleted file mode 100644 index 6aac1d3..0000000 --- a/modules/usbaudio/format.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright (C) 2014 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_profile" -/*#define LOG_NDEBUG 0*/ - -#include "format.h" - -#include <tinyalsa/asoundlib.h> - -#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) - -/* - * Maps from bit position in pcm_mask to AUDIO_ format constants. - */ -static audio_format_t const format_value_map[] = { - AUDIO_FORMAT_PCM_8_BIT, /* 00 - SNDRV_PCM_FORMAT_S8 */ - AUDIO_FORMAT_PCM_8_BIT, /* 01 - SNDRV_PCM_FORMAT_U8 */ - AUDIO_FORMAT_PCM_16_BIT, /* 02 - SNDRV_PCM_FORMAT_S16_LE */ - AUDIO_FORMAT_INVALID, /* 03 - SNDRV_PCM_FORMAT_S16_BE */ - AUDIO_FORMAT_INVALID, /* 04 - SNDRV_PCM_FORMAT_U16_LE */ - AUDIO_FORMAT_INVALID, /* 05 - SNDRV_PCM_FORMAT_U16_BE */ - AUDIO_FORMAT_INVALID, /* 06 - SNDRV_PCM_FORMAT_S24_LE */ - AUDIO_FORMAT_INVALID, /* 07 - SNDRV_PCM_FORMAT_S24_BE */ - AUDIO_FORMAT_INVALID, /* 08 - SNDRV_PCM_FORMAT_U24_LE */ - AUDIO_FORMAT_INVALID, /* 09 - SNDRV_PCM_FORMAT_U24_BE */ - AUDIO_FORMAT_PCM_32_BIT, /* 10 - SNDRV_PCM_FORMAT_S32_LE */ - AUDIO_FORMAT_INVALID, /* 11 - SNDRV_PCM_FORMAT_S32_BE */ - AUDIO_FORMAT_INVALID, /* 12 - SNDRV_PCM_FORMAT_U32_LE */ - AUDIO_FORMAT_INVALID, /* 13 - SNDRV_PCM_FORMAT_U32_BE */ - AUDIO_FORMAT_PCM_FLOAT, /* 14 - SNDRV_PCM_FORMAT_FLOAT_LE */ - AUDIO_FORMAT_INVALID, /* 15 - SNDRV_PCM_FORMAT_FLOAT_BE */ - AUDIO_FORMAT_INVALID, /* 16 - SNDRV_PCM_FORMAT_FLOAT64_LE */ - AUDIO_FORMAT_INVALID, /* 17 - SNDRV_PCM_FORMAT_FLOAT64_BE */ - AUDIO_FORMAT_INVALID, /* 18 - SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE */ - AUDIO_FORMAT_INVALID, /* 19 - SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE */ - AUDIO_FORMAT_INVALID, /* 20 - SNDRV_PCM_FORMAT_MU_LAW */ - AUDIO_FORMAT_INVALID, /* 21 - SNDRV_PCM_FORMAT_A_LAW */ - AUDIO_FORMAT_INVALID, /* 22 - SNDRV_PCM_FORMAT_IMA_ADPCM */ - AUDIO_FORMAT_INVALID, /* 23 - SNDRV_PCM_FORMAT_MPEG */ - AUDIO_FORMAT_INVALID, /* 24 - SNDRV_PCM_FORMAT_GSM */ - AUDIO_FORMAT_INVALID, /* 25 -> 30 (not assigned) */ - AUDIO_FORMAT_INVALID, - AUDIO_FORMAT_INVALID, - AUDIO_FORMAT_INVALID, - AUDIO_FORMAT_INVALID, - AUDIO_FORMAT_INVALID, - AUDIO_FORMAT_INVALID, /* 31 - SNDRV_PCM_FORMAT_SPECIAL */ - AUDIO_FORMAT_PCM_24_BIT_PACKED, /* 32 - SNDRV_PCM_FORMAT_S24_3LE */ - AUDIO_FORMAT_INVALID, /* 33 - SNDRV_PCM_FORMAT_S24_3BE */ - AUDIO_FORMAT_INVALID, /* 34 - SNDRV_PCM_FORMAT_U24_3LE */ - AUDIO_FORMAT_INVALID, /* 35 - SNDRV_PCM_FORMAT_U24_3BE */ - AUDIO_FORMAT_INVALID, /* 36 - SNDRV_PCM_FORMAT_S20_3LE */ - AUDIO_FORMAT_INVALID, /* 37 - SNDRV_PCM_FORMAT_S20_3BE */ - AUDIO_FORMAT_INVALID, /* 38 - SNDRV_PCM_FORMAT_U20_3LE */ - AUDIO_FORMAT_INVALID, /* 39 - SNDRV_PCM_FORMAT_U20_3BE */ - AUDIO_FORMAT_INVALID, /* 40 - SNDRV_PCM_FORMAT_S18_3LE */ - AUDIO_FORMAT_INVALID, /* 41 - SNDRV_PCM_FORMAT_S18_3BE */ - AUDIO_FORMAT_INVALID, /* 42 - SNDRV_PCM_FORMAT_U18_3LE */ - AUDIO_FORMAT_INVALID, /* 43 - SNDRV_PCM_FORMAT_U18_3BE */ - AUDIO_FORMAT_INVALID, /* 44 - SNDRV_PCM_FORMAT_G723_24 */ - AUDIO_FORMAT_INVALID, /* 45 - SNDRV_PCM_FORMAT_G723_24_1B */ - AUDIO_FORMAT_INVALID, /* 46 - SNDRV_PCM_FORMAT_G723_40 */ - AUDIO_FORMAT_INVALID, /* 47 - SNDRV_PCM_FORMAT_G723_40_1B */ - AUDIO_FORMAT_INVALID, /* 48 - SNDRV_PCM_FORMAT_DSD_U8 */ - AUDIO_FORMAT_INVALID /* 49 - SNDRV_PCM_FORMAT_DSD_U16_LE */ -}; - -audio_format_t get_format_for_mask(struct pcm_mask* mask) -{ - int num_slots = sizeof(mask->bits) / sizeof(mask->bits[0]); - int bits_per_slot = sizeof(mask->bits[0]) * 8; - - int table_size = sizeof(format_value_map) / sizeof(format_value_map[0]); - - int slot_index, bit_index, table_index; - table_index = 0; - int num_written = 0; - for (slot_index = 0; slot_index < num_slots; slot_index++) { - unsigned bit_mask = 1; - for (bit_index = 0; bit_index < bits_per_slot; bit_index++) { - /* don't return b-bit formats even if they are supported */ - if (table_index >= 2 && (mask->bits[slot_index] & bit_mask) != 0) { - /* just return the first one */ - return table_index < table_size - ? format_value_map[table_index] - : AUDIO_FORMAT_INVALID; - } - bit_mask <<= 1; - table_index++; - } - } - - return AUDIO_FORMAT_INVALID; -} - -/* - * Maps from bit position in pcm_mask to PCM_ format constants. - */ -int8_t const pcm_format_value_map[50] = { - PCM_FORMAT_S8, /* 00 - SNDRV_PCM_FORMAT_S8 */ - PCM_FORMAT_INVALID, /* 01 - SNDRV_PCM_FORMAT_U8 */ - PCM_FORMAT_S16_LE, /* 02 - SNDRV_PCM_FORMAT_S16_LE */ - PCM_FORMAT_INVALID, /* 03 - SNDRV_PCM_FORMAT_S16_BE */ - PCM_FORMAT_INVALID, /* 04 - SNDRV_PCM_FORMAT_U16_LE */ - PCM_FORMAT_INVALID, /* 05 - SNDRV_PCM_FORMAT_U16_BE */ - PCM_FORMAT_S24_3LE, /* 06 - SNDRV_PCM_FORMAT_S24_LE */ - PCM_FORMAT_INVALID, /* 07 - SNDRV_PCM_FORMAT_S24_BE */ - PCM_FORMAT_INVALID, /* 08 - SNDRV_PCM_FORMAT_U24_LE */ - PCM_FORMAT_INVALID, /* 09 - SNDRV_PCM_FORMAT_U24_BE */ - PCM_FORMAT_S32_LE, /* 10 - SNDRV_PCM_FORMAT_S32_LE */ - PCM_FORMAT_INVALID, /* 11 - SNDRV_PCM_FORMAT_S32_BE */ - PCM_FORMAT_INVALID, /* 12 - SNDRV_PCM_FORMAT_U32_LE */ - PCM_FORMAT_INVALID, /* 13 - SNDRV_PCM_FORMAT_U32_BE */ - PCM_FORMAT_INVALID, /* 14 - SNDRV_PCM_FORMAT_FLOAT_LE */ - PCM_FORMAT_INVALID, /* 15 - SNDRV_PCM_FORMAT_FLOAT_BE */ - PCM_FORMAT_INVALID, /* 16 - SNDRV_PCM_FORMAT_FLOAT64_LE */ - PCM_FORMAT_INVALID, /* 17 - SNDRV_PCM_FORMAT_FLOAT64_BE */ - PCM_FORMAT_INVALID, /* 18 - SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE */ - PCM_FORMAT_INVALID, /* 19 - SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE */ - PCM_FORMAT_INVALID, /* 20 - SNDRV_PCM_FORMAT_MU_LAW */ - PCM_FORMAT_INVALID, /* 21 - SNDRV_PCM_FORMAT_A_LAW */ - PCM_FORMAT_INVALID, /* 22 - SNDRV_PCM_FORMAT_IMA_ADPCM */ - PCM_FORMAT_INVALID, /* 23 - SNDRV_PCM_FORMAT_MPEG */ - PCM_FORMAT_INVALID, /* 24 - SNDRV_PCM_FORMAT_GSM */ - PCM_FORMAT_INVALID, /* 25 -> 30 (not assigned) */ - PCM_FORMAT_INVALID, - PCM_FORMAT_INVALID, - PCM_FORMAT_INVALID, - PCM_FORMAT_INVALID, - PCM_FORMAT_INVALID, - PCM_FORMAT_INVALID, /* 31 - SNDRV_PCM_FORMAT_SPECIAL */ - PCM_FORMAT_S24_3LE, /* 32 - SNDRV_PCM_FORMAT_S24_3LE */ /* ??? */ - PCM_FORMAT_INVALID, /* 33 - SNDRV_PCM_FORMAT_S24_3BE */ - PCM_FORMAT_INVALID, /* 34 - SNDRV_PCM_FORMAT_U24_3LE */ - PCM_FORMAT_INVALID, /* 35 - SNDRV_PCM_FORMAT_U24_3BE */ - PCM_FORMAT_INVALID, /* 36 - SNDRV_PCM_FORMAT_S20_3LE */ - PCM_FORMAT_INVALID, /* 37 - SNDRV_PCM_FORMAT_S20_3BE */ - PCM_FORMAT_INVALID, /* 38 - SNDRV_PCM_FORMAT_U20_3LE */ - PCM_FORMAT_INVALID, /* 39 - SNDRV_PCM_FORMAT_U20_3BE */ - PCM_FORMAT_INVALID, /* 40 - SNDRV_PCM_FORMAT_S18_3LE */ - PCM_FORMAT_INVALID, /* 41 - SNDRV_PCM_FORMAT_S18_3BE */ - PCM_FORMAT_INVALID, /* 42 - SNDRV_PCM_FORMAT_U18_3LE */ - PCM_FORMAT_INVALID, /* 43 - SNDRV_PCM_FORMAT_U18_3BE */ - PCM_FORMAT_INVALID, /* 44 - SNDRV_PCM_FORMAT_G723_24 */ - PCM_FORMAT_INVALID, /* 45 - SNDRV_PCM_FORMAT_G723_24_1B */ - PCM_FORMAT_INVALID, /* 46 - SNDRV_PCM_FORMAT_G723_40 */ - PCM_FORMAT_INVALID, /* 47 - SNDRV_PCM_FORMAT_G723_40_1B */ - PCM_FORMAT_INVALID, /* 48 - SNDRV_PCM_FORMAT_DSD_U8 */ - PCM_FORMAT_INVALID /* 49 - SNDRV_PCM_FORMAT_DSD_U16_LE */ -}; - -/* - * Scans the provided format mask and returns the first non-8 bit sample - * format supported by the devices. - */ -enum pcm_format get_pcm_format_for_mask(struct pcm_mask* mask) -{ - int num_slots = ARRAY_SIZE(mask->bits); - int bits_per_slot = sizeof(mask->bits[0]) * 8; - - int table_size = ARRAY_SIZE(pcm_format_value_map); - - int slot_index, bit_index, table_index; - table_index = 0; - int num_written = 0; - for (slot_index = 0; slot_index < num_slots && table_index < table_size; slot_index++) { - unsigned bit_mask = 1; - for (bit_index = 0; bit_index < bits_per_slot && table_index < table_size; bit_index++) { - /* skip any 8-bit formats */ - if (table_index >= 2 && (mask->bits[slot_index] & bit_mask) != 0) { - /* just return the first one which will be at least 16-bit */ - return (int)pcm_format_value_map[table_index]; - } - bit_mask <<= 1; - table_index++; - } - } - - return PCM_FORMAT_INVALID; -} diff --git a/modules/usbaudio/format.h b/modules/usbaudio/format.h deleted file mode 100644 index e23935e..0000000 --- a/modules/usbaudio/format.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2014 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. - */ - -#ifndef ANDROID_HARDWARE_LIBHARDWARE_MODULES_USBAUDIO_FORMAT_H -#define ANDROID_HARDWARE_LIBHARDWARE_MODULES_USBAUDIO_FORMAT_H - -#include <system/audio.h> - -#include <tinyalsa/asoundlib.h> - -audio_format_t get_format_for_mask(struct pcm_mask* mask); -enum pcm_format get_pcm_format_for_mask(struct pcm_mask* mask); - -#endif /* ANDROID_HARDWARE_LIBHARDWARE_MODULES_USBAUDIO_FORMAT_H */ diff --git a/modules/usbaudio/logging.c b/modules/usbaudio/logging.c deleted file mode 100644 index 0a05511..0000000 --- a/modules/usbaudio/logging.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (C) 2014 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_logging" -/*#define LOG_NDEBUG 0*/ - -#include <string.h> - -#include <log/log.h> - -#include "logging.h" - -#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) - -/* - * Logging - */ -void log_pcm_mask(const char* mask_name, struct pcm_mask* mask) -{ - const size_t num_slots = ARRAY_SIZE(mask->bits); - const size_t bits_per_slot = (sizeof(mask->bits[0]) * 8); - const size_t chars_per_slot = (bits_per_slot + 1); /* comma */ - - const size_t BUFF_SIZE = - (num_slots * chars_per_slot + 2 + 1); /* brackets and null-terminator */ - char buff[BUFF_SIZE]; - buff[0] = '\0'; - - size_t slot_index, bit_index; - strcat(buff, "["); - for (slot_index = 0; slot_index < num_slots; slot_index++) { - unsigned bit_mask = 1; - for (bit_index = 0; bit_index < bits_per_slot; bit_index++) { - strcat(buff, (mask->bits[slot_index] & bit_mask) != 0 ? "1" : "0"); - bit_mask <<= 1; - } - if (slot_index < num_slots - 1) { - strcat(buff, ","); - } - } - strcat(buff, "]"); - - ALOGV("%s: mask:%s", mask_name, buff); -} - -void log_pcm_params(struct pcm_params * alsa_hw_params) -{ - ALOGV("usb:audio_hw - PCM_PARAM_SAMPLE_BITS min:%u, max:%u", - pcm_params_get_min(alsa_hw_params, PCM_PARAM_SAMPLE_BITS), - pcm_params_get_max(alsa_hw_params, PCM_PARAM_SAMPLE_BITS)); - ALOGV("usb:audio_hw - PCM_PARAM_FRAME_BITS min:%u, max:%u", - pcm_params_get_min(alsa_hw_params, PCM_PARAM_FRAME_BITS), - pcm_params_get_max(alsa_hw_params, PCM_PARAM_FRAME_BITS)); - log_pcm_mask("PCM_PARAM_FORMAT", - pcm_params_get_mask(alsa_hw_params, PCM_PARAM_FORMAT)); - log_pcm_mask("PCM_PARAM_SUBFORMAT", - pcm_params_get_mask(alsa_hw_params, PCM_PARAM_SUBFORMAT)); - ALOGV("usb:audio_hw - PCM_PARAM_CHANNELS min:%u, max:%u", - pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS), - pcm_params_get_max(alsa_hw_params, PCM_PARAM_CHANNELS)); - ALOGV("usb:audio_hw - PCM_PARAM_RATE min:%u, max:%u", - pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE), - pcm_params_get_max(alsa_hw_params, PCM_PARAM_RATE)); - ALOGV("usb:audio_hw - PCM_PARAM_PERIOD_TIME min:%u, max:%u", - pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIOD_TIME), - pcm_params_get_max(alsa_hw_params, PCM_PARAM_PERIOD_TIME)); - ALOGV("usb:audio_hw - PCM_PARAM_PERIOD_SIZE min:%u, max:%u", - pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIOD_SIZE), - pcm_params_get_max(alsa_hw_params, PCM_PARAM_PERIOD_SIZE)); - ALOGV("usb:audio_hw - PCM_PARAM_PERIOD_BYTES min:%u, max:%u", - pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIOD_BYTES), - pcm_params_get_max(alsa_hw_params, PCM_PARAM_PERIOD_BYTES)); - ALOGV("usb:audio_hw - PCM_PARAM_PERIODS min:%u, max:%u", - pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIODS), - pcm_params_get_max(alsa_hw_params, PCM_PARAM_PERIODS)); - ALOGV("usb:audio_hw - PCM_PARAM_BUFFER_TIME min:%u, max:%u", - pcm_params_get_min(alsa_hw_params, PCM_PARAM_BUFFER_TIME), - pcm_params_get_max(alsa_hw_params, PCM_PARAM_BUFFER_TIME)); - ALOGV("usb:audio_hw - PCM_PARAM_BUFFER_SIZE min:%u, max:%u", - pcm_params_get_min(alsa_hw_params, PCM_PARAM_BUFFER_SIZE), - pcm_params_get_max(alsa_hw_params, PCM_PARAM_BUFFER_SIZE)); - ALOGV("usb:audio_hw - PCM_PARAM_BUFFER_BYTES min:%u, max:%u", - pcm_params_get_min(alsa_hw_params, PCM_PARAM_BUFFER_BYTES), - pcm_params_get_max(alsa_hw_params, PCM_PARAM_BUFFER_BYTES)); - ALOGV("usb:audio_hw - PCM_PARAM_TICK_TIME min:%u, max:%u", - pcm_params_get_min(alsa_hw_params, PCM_PARAM_TICK_TIME), - pcm_params_get_max(alsa_hw_params, PCM_PARAM_TICK_TIME)); -} - -void log_pcm_config(struct pcm_config * config, const char* label) { - ALOGV("log_pcm_config() - %s", label); - ALOGV(" channels:%d", config->channels); - ALOGV(" rate:%d", config->rate); - ALOGV(" period_size:%d", config->period_size); - ALOGV(" period_count:%d", config->period_count); - ALOGV(" format:%d", config->format); -#if 0 - /* Values to use for the ALSA start, stop and silence thresholds. Setting - * any one of these values to 0 will cause the default tinyalsa values to be - * used instead. Tinyalsa defaults are as follows. - * - * start_threshold : period_count * period_size - * stop_threshold : period_count * period_size - * silence_threshold : 0 - */ - unsigned int start_threshold; - unsigned int stop_threshold; - unsigned int silence_threshold; - - /* Minimum number of frames available before pcm_mmap_write() will actually - * write into the kernel buffer. Only used if the stream is opened in mmap mode - * (pcm_open() called with PCM_MMAP flag set). Use 0 for default. - */ - int avail_min; -#endif -} diff --git a/modules/usbaudio/logging.h b/modules/usbaudio/logging.h deleted file mode 100644 index b5640ed..0000000 --- a/modules/usbaudio/logging.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2014 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. - */ - -#ifndef ANDROID_HARDWARE_LIBHARDWARE_MODULES_USBAUDIO_LOGGING_H -#define ANDROID_HARDWARE_LIBHARDWARE_MODULES_USBAUDIO_LOGGING_H - -#include <tinyalsa/asoundlib.h> - -void log_pcm_mask(const char* mask_name, struct pcm_mask* mask); -void log_pcm_params(struct pcm_params * alsa_hw_params); -void log_pcm_config(struct pcm_config * config, const char* label); - -#endif /* ANDROID_HARDWARE_LIBHARDWARE_MODULES_USBAUDIO_LOGGING_H */ diff --git a/modules/usbcamera/Android.mk b/modules/usbcamera/Android.mk new file mode 100644 index 0000000..162b158 --- /dev/null +++ b/modules/usbcamera/Android.mk @@ -0,0 +1,45 @@ +# Copyright (C) 2015 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 := camera.usb.default +LOCAL_MODULE_RELATIVE_PATH := hw + +LOCAL_C_INCLUDES += \ + system/core/include \ + system/media/camera/include \ + +LOCAL_SRC_FILES := \ + CameraHAL.cpp \ + Camera.cpp \ + UsbCamera.cpp \ + Metadata.cpp \ + Stream.cpp \ + HotplugThread.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + libcamera_metadata \ + libcutils \ + liblog \ + libsync \ + libutils \ + +LOCAL_CFLAGS += -Wall -Wextra -fvisibility=hidden + +LOCAL_MODULE_TAGS := optional + +include $(BUILD_SHARED_LIBRARY) diff --git a/modules/usbcamera/Camera.cpp b/modules/usbcamera/Camera.cpp new file mode 100644 index 0000000..cf62f7f --- /dev/null +++ b/modules/usbcamera/Camera.cpp @@ -0,0 +1,537 @@ +/* + * Copyright (C) 2015 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_NDEBUG 0 +#define LOG_TAG "Camera" +#include <cutils/log.h> + +#include <cstdlib> +#include <stdio.h> +#include <hardware/camera3.h> +#include <system/camera_metadata.h> +#include <system/graphics.h> +#include <utils/Mutex.h> +#include "CameraHAL.h" +#include "Metadata.h" +#include "Stream.h" + +#define ATRACE_TAG (ATRACE_TAG_CAMERA | ATRACE_TAG_HAL) +#include <utils/Trace.h> + +#include "Camera.h" + +namespace usb_camera_hal { + +extern "C" { +// Shim passed to the framework to close an opened device. +static int close_device(hw_device_t* dev) { + camera3_device_t* cam_dev = reinterpret_cast<camera3_device_t*>(dev); + Camera* cam = static_cast<Camera*>(cam_dev->priv); + return cam->close(); +} + +// Get handle to camera from device priv data +static Camera *camdev_to_camera(const camera3_device_t *dev) { + return reinterpret_cast<Camera*>(dev->priv); +} + +static int initialize(const camera3_device_t *dev, + const camera3_callback_ops_t *callback_ops) { + return camdev_to_camera(dev)->initialize(callback_ops); +} + +static int configure_streams(const camera3_device_t *dev, + camera3_stream_configuration_t *stream_list) { + return camdev_to_camera(dev)->configureStreams(stream_list); +} + +static const camera_metadata_t *construct_default_request_settings( + const camera3_device_t *dev, int type) { + return camdev_to_camera(dev)->constructDefaultRequestSettings(type); +} + +static int process_capture_request(const camera3_device_t *dev, + camera3_capture_request_t *request) { + return camdev_to_camera(dev)->processCaptureRequest(request); +} + +static void dump(const camera3_device_t *dev, int fd) { + camdev_to_camera(dev)->dump(fd); +} + +static int flush(const camera3_device_t *dev) { + return camdev_to_camera(dev)->flush(); +} + +} // extern "C" + +const camera3_device_ops_t Camera::sOps = { + .initialize = usb_camera_hal::initialize, + .configure_streams = usb_camera_hal::configure_streams, + .register_stream_buffers = NULL, + .construct_default_request_settings + = usb_camera_hal::construct_default_request_settings, + .process_capture_request = usb_camera_hal::process_capture_request, + .get_metadata_vendor_tag_ops = NULL, + .dump = usb_camera_hal::dump, + .flush = usb_camera_hal::flush, + .reserved = {0}, +}; + +Camera::Camera(int id) + : mId(id), + mStaticInfo(NULL), + mBusy(false), + mCallbackOps(NULL), + mSettings(NULL), + mIsInitialized(false) { + memset(&mTemplates, 0, sizeof(mTemplates)); + memset(&mDevice, 0, sizeof(mDevice)); + mDevice.common.tag = HARDWARE_DEVICE_TAG; + // TODO: Upgrade to HAL3.3 + mDevice.common.version = CAMERA_DEVICE_API_VERSION_3_2; + mDevice.common.close = close_device; + mDevice.ops = const_cast<camera3_device_ops_t*>(&sOps); + mDevice.priv = this; +} + +Camera::~Camera() { + if (mStaticInfo != NULL) { + free_camera_metadata(mStaticInfo); + } + + for (int i = 0; i < CAMERA3_TEMPLATE_COUNT; i++) { + free_camera_metadata(mTemplates[i]); + } + + if (mSettings != NULL) { + free_camera_metadata(mSettings); + } +} + +int Camera::open(const hw_module_t *module, hw_device_t **device) { + ALOGI("%s:%d: Opening camera device", __func__, mId); + ATRACE_CALL(); + android::Mutex::Autolock al(mDeviceLock); + + if (mBusy) { + ALOGE("%s:%d: Error! Camera device already opened", __func__, mId); + return -EBUSY; + } + + mBusy = true; + mDevice.common.module = const_cast<hw_module_t*>(module); + *device = &mDevice.common; + return openDevice(); +} + +int Camera::getInfo(struct camera_info *info) { + android::Mutex::Autolock al(mStaticInfoLock); + + // TODO: update to CAMERA_FACING_EXTERNAL once the HAL API changes are merged. + info->facing = CAMERA_FACING_FRONT; + info->orientation = 0; + info->device_version = mDevice.common.version; + if (mStaticInfo == NULL) { + initStaticInfo(); + } + info->static_camera_characteristics = mStaticInfo; + return 0; +} + +void Camera::updateInfo() { + android::Mutex::Autolock al(mStaticInfoLock); + initStaticInfo(); +} + +int Camera::close() { + ALOGI("%s:%d: Closing camera device", __func__, mId); + ATRACE_CALL(); + android::Mutex::Autolock al(mDeviceLock); + + if (!mBusy) { + ALOGE("%s:%d: Error! Camera device not open", __func__, mId); + return -EINVAL; + } + + mBusy = false; + mIsInitialized = false; + return closeDevice(); +} + +int Camera::initialize(const camera3_callback_ops_t *callback_ops) { + int res; + + ALOGV("%s:%d: callback_ops=%p", __func__, mId, callback_ops); + ATRACE_CALL(); + android::Mutex::Autolock al(mDeviceLock); + + mCallbackOps = callback_ops; + // per-device specific initialization + res = initDevice(); + if (res != 0) { + ALOGE("%s:%d: Failed to initialize device!", __func__, mId); + return res; + } + + mIsInitialized = true; + return 0; +} + +int Camera::configureStreams(camera3_stream_configuration_t *stream_config) { + camera3_stream_t *astream; + android::Vector<Stream *> newStreams; + + ALOGV("%s:%d: stream_config=%p", __func__, mId, stream_config); + ATRACE_CALL(); + android::Mutex::Autolock al(mDeviceLock); + if (!mIsInitialized) { + ALOGE("Device is not initialized yet"); + return -EINVAL; + } + + if (stream_config == NULL) { + ALOGE("%s:%d: NULL stream configuration array", __func__, mId); + return -EINVAL; + } + if (stream_config->num_streams == 0) { + ALOGE("%s:%d: Empty stream configuration array", __func__, mId); + return -EINVAL; + } + + ALOGV("%s:%d: Number of Streams: %d", __func__, mId, + stream_config->num_streams); + // Mark all current streams unused for now + for (size_t i = 0; i < mStreams.size(); i++) { + mStreams[i]->mReuse = false; + } + // Fill new stream array with reused streams and new streams + for (unsigned int i = 0; i < stream_config->num_streams; i++) { + astream = stream_config->streams[i]; + if (astream->max_buffers > 0) { + ALOGV("%s:%d: Reusing stream %d", __func__, mId, i); + newStreams.add(reuseStreamLocked(astream)); + } else { + ALOGV("%s:%d: Creating new stream %d", __func__, mId, i); + newStreams.add(new Stream(mId, astream)); + } + + if (newStreams[i] == NULL) { + ALOGE("%s:%d: Error processing stream %d", __func__, mId, i); + goto err_out; + } + astream->priv = reinterpret_cast<void *>(newStreams[i]); + } + + // Verify the set of streams in aggregate + if (!isValidStreamSetLocked(newStreams)) { + ALOGE("%s:%d: Invalid stream set", __func__, mId); + goto err_out; + } + + // Set up all streams (calculate usage/max_buffers for each) + setupStreamsLocked(newStreams); + + // Destroy all old streams and replace stream array with new one + destroyStreamsLocked(mStreams); + mStreams = newStreams; + + // Clear out last seen settings metadata + updateSettingsLocked(NULL); + return 0; + +err_out: + // Clean up temporary streams, preserve existing mStreams + destroyStreamsLocked(newStreams); + return -EINVAL; +} + +void Camera::destroyStreamsLocked(android::Vector<Stream *> &streams) { + for (size_t i = 0; i < streams.size(); i++) { + delete streams[i]; + } + streams.clear(); +} + +Stream *Camera::reuseStreamLocked(camera3_stream_t *astream) { + Stream *priv = reinterpret_cast<Stream*>(astream->priv); + // Verify the re-used stream's parameters match + if (!priv->isValidReuseStream(mId, astream)) { + ALOGE("%s:%d: Mismatched parameter in reused stream", __func__, mId); + return NULL; + } + // Mark stream to be reused + priv->mReuse = true; + return priv; +} + +bool Camera::isValidStreamSetLocked(const android::Vector<Stream *> &streams) { + int inputs = 0; + int outputs = 0; + + if (streams.isEmpty()) { + ALOGE("%s:%d: Zero count stream configuration streams", __func__, mId); + return false; + } + // Validate there is at most one input stream and at least one output stream + for (size_t i = 0; i < streams.size(); i++) { + // A stream may be both input and output (bidirectional) + if (streams[i]->isInputType()) + inputs++; + if (streams[i]->isOutputType()) + outputs++; + } + ALOGV("%s:%d: Configuring %d output streams and %d input streams", + __func__, mId, outputs, inputs); + if (outputs < 1) { + ALOGE("%s:%d: Stream config must have >= 1 output", __func__, mId); + return false; + } + if (inputs > 1) { + ALOGE("%s:%d: Stream config must have <= 1 input", __func__, mId); + return false; + } + // TODO: check for correct number of Bayer/YUV/JPEG/Encoder streams + return true; +} + +void Camera::setupStreamsLocked(android::Vector<Stream *> &streams) { + /* + * This is where the HAL has to decide internally how to handle all of the + * streams, and then produce usage and max_buffer values for each stream. + * Note, the stream vector has been checked before this point for ALL invalid + * conditions, so it must find a successful configuration for this stream + * array. The HAL may not return an error from this point. + * + * TODO: we just set all streams to be the same dummy values; + * real implementations will want to avoid USAGE_SW_{READ|WRITE}_OFTEN. + */ + for (size_t i = 0; i < streams.size(); i++) { + uint32_t usage = 0; + + if (streams[i]->isOutputType()) + usage |= GRALLOC_USAGE_SW_WRITE_OFTEN | + GRALLOC_USAGE_HW_CAMERA_WRITE; + if (streams[i]->isInputType()) + usage |= GRALLOC_USAGE_SW_READ_OFTEN | + GRALLOC_USAGE_HW_CAMERA_READ; + + streams[i]->setUsage(usage); + streams[i]->setMaxBuffers(1); + } +} + +bool Camera::isValidTemplateType(int type) { + return type >= 1 && type < CAMERA3_TEMPLATE_COUNT; +} + +const camera_metadata_t* Camera::constructDefaultRequestSettings(int type) { + ALOGV("%s:%d: type=%d", __func__, mId, type); + android::Mutex::Autolock al(mDeviceLock); + + if (!isValidTemplateType(type)) { + ALOGE("%s:%d: Invalid template request type: %d", __func__, mId, type); + return NULL; + } + + // DO NOT try to initialize the device here, it will be guaranteed deadlock. + if (!mIsInitialized) { + ALOGE("Device is not initialized yet"); + return NULL; + } + + return mTemplates[type]; +} + +// This implementation is a copy-paste, probably we should override (or move) this to +// device specific class. +int Camera::processCaptureRequest(camera3_capture_request_t *request) { + camera3_capture_result result; + ALOGV("%s:%d: request=%p", __func__, mId, request); + ATRACE_CALL(); + android::Mutex::Autolock al(mDeviceLock); + + if (request == NULL) { + ALOGE("%s:%d: NULL request recieved", __func__, mId); + return -EINVAL; + } + + ALOGV("%s:%d: Request Frame:%d Settings:%p", __func__, mId, + request->frame_number, request->settings); + + // NULL indicates use last settings + if (request->settings == NULL) { + if (mSettings == NULL) { + ALOGE("%s:%d: NULL settings without previous set Frame:%d Req:%p", + __func__, mId, request->frame_number, request); + return -EINVAL; + } + } else { + updateSettingsLocked(request->settings); + } + + if (request->input_buffer != NULL) { + ALOGV("%s:%d: Reprocessing input buffer is not supported yet", __func__, mId); + return -EINVAL; + } else { + ALOGV("%s:%d: Capturing new frame.", __func__, mId); + + if (!isValidCaptureSettings(request->settings)) { + ALOGE("%s:%d: Invalid settings for capture request: %p", + __func__, mId, request->settings); + return -EINVAL; + } + } + + if (request->num_output_buffers <= 0) { + ALOGE("%s:%d: Invalid number of output buffers: %d", __func__, mId, + request->num_output_buffers); + return -EINVAL; + } + result.num_output_buffers = request->num_output_buffers; + result.output_buffers = new camera3_stream_buffer_t[result.num_output_buffers]; + for (unsigned int i = 0; i < request->num_output_buffers; i++) { + int res = processCaptureBuffer(&request->output_buffers[i], + const_cast<camera3_stream_buffer_t*>(&result.output_buffers[i])); + if (res) { + delete [] result.output_buffers; + // TODO: this should probably be a total device failure; transient for now + return -EINVAL; + } + } + + result.frame_number = request->frame_number; + // TODO: return actual captured/reprocessed settings + result.result = request->settings; + // TODO: asynchronously return results + notifyShutter(request->frame_number, 0); + mCallbackOps->process_capture_result(mCallbackOps, &result); + + // Free up capture result related resources, HAL owns the capture result, and it + // is only valid during the process_capture_result call. + delete[] result.output_buffers; + + return 0; +} + +int Camera::flush() { + int res; + + ALOGV("%s:%d: flush device", __func__, mId); + // per-device specific flush + res = flushDevice(); + if (res != 0) { + ALOGE("%s:%d: Failed to flush device!", __func__, mId); + return res; + } + return 0; +} + +void Camera::updateSettingsLocked(const camera_metadata_t *new_settings) { + if (mSettings != NULL) { + free_camera_metadata(mSettings); + mSettings = NULL; + } + + if (new_settings != NULL) + mSettings = clone_camera_metadata(new_settings); +} + +void Camera::notifyShutter(uint32_t frame_number, uint64_t timestamp) { + int res; + struct timespec ts; + + // If timestamp is 0, get timestamp from right now instead + if (timestamp == 0) { + ALOGW("%s:%d: No timestamp provided, using CLOCK_BOOTTIME", + __func__, mId); + res = clock_gettime(CLOCK_BOOTTIME, &ts); + if (res == 0) { + timestamp = ts.tv_sec * 1000000000ULL + ts.tv_nsec; + } else { + ALOGE("%s:%d: No timestamp and failed to get CLOCK_BOOTTIME %s(%d)", + __func__, mId, strerror(errno), errno); + } + } + camera3_notify_msg_t m; + memset(&m, 0, sizeof(m)); + m.type = CAMERA3_MSG_SHUTTER; + m.message.shutter.frame_number = frame_number; + m.message.shutter.timestamp = timestamp; + mCallbackOps->notify(mCallbackOps, &m); +} + +void Camera::dump(int fd) { + ALOGV("%s:%d: Dumping to fd %d", __func__, mId, fd); + ATRACE_CALL(); + android::Mutex::Autolock al(mDeviceLock); + + dprintf(fd, "Camera ID: %d (Busy: %d)\n", mId, mBusy); + + // TODO: dump all settings + dprintf(fd, "Most Recent Settings: (%p)\n", mSettings); + + dprintf(fd, "Number of streams: %d\n", mStreams.size()); + for (size_t i = 0; i < mStreams.size(); i++) { + dprintf(fd, "Stream %d/%d:\n", i, mStreams.size()); + mStreams[i]->dump(fd); + } +} + +const char* Camera::templateToString(int type) { + switch (type) { + case CAMERA3_TEMPLATE_PREVIEW: + return "CAMERA3_TEMPLATE_PREVIEW"; + case CAMERA3_TEMPLATE_STILL_CAPTURE: + return "CAMERA3_TEMPLATE_STILL_CAPTURE"; + case CAMERA3_TEMPLATE_VIDEO_RECORD: + return "CAMERA3_TEMPLATE_VIDEO_RECORD"; + case CAMERA3_TEMPLATE_VIDEO_SNAPSHOT: + return "CAMERA3_TEMPLATE_VIDEO_SNAPSHOT"; + case CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG: + return "CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG"; + case CAMERA3_TEMPLATE_MANUAL: + return "CAMERA3_TEMPLATE_MANUAL"; + } + + return "Invalid template type!"; +} + +int Camera::setTemplate(int type, camera_metadata_t *settings) { + android::Mutex::Autolock al(mDeviceLock); + + if (!isValidTemplateType(type)) { + ALOGE("%s:%d: Invalid template request type: %d", __func__, mId, type); + return -EINVAL; + } + + if (mTemplates[type] != NULL) { + ALOGE("%s:%d: Setting already constructed template type %s(%d)", + __func__, mId, templateToString(type), type); + return -EINVAL; + } + + // Make a durable copy of the underlying metadata + mTemplates[type] = clone_camera_metadata(settings); + if (mTemplates[type] == NULL) { + ALOGE("%s:%d: Failed to clone metadata %p for template type %s(%d)", + __func__, mId, settings, templateToString(type), type); + return -EINVAL; + } + return 0; +} + +} // namespace usb_camera_hal diff --git a/modules/usbcamera/Camera.h b/modules/usbcamera/Camera.h new file mode 100644 index 0000000..6419c7d --- /dev/null +++ b/modules/usbcamera/Camera.h @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef CAMERA_H_ +#define CAMERA_H_ + +#include <hardware/hardware.h> +#include <hardware/camera3.h> +#include <utils/Mutex.h> +#include <utils/Vector.h> +#include "Metadata.h" +#include <sync/sync.h> +#include "Stream.h" + +#define CAMERA_SYNC_TIMEOUT_MS 5000 + +namespace usb_camera_hal { +// Camera represents a physical camera on a device. +// This is constructed when the HAL module is loaded, one per physical camera. +// It is opened by the framework, and must be closed before it can be opened +// again. +// This is an abstract class, containing all logic and data shared between all +// camera devices. +class Camera { + public: + // id is used to distinguish cameras. 0 <= id < NUM_CAMERAS. + // module is a handle to the HAL module, used when the device is opened. + Camera(int id); + virtual ~Camera(); + + // Common Camera Device Operations (see <hardware/camera_common.h>) + int open(const hw_module_t *module, hw_device_t **device); + int getInfo(struct camera_info *info); + int close(); + + // Camera v3 Device Operations (see <hardware/camera3.h>) + int initialize(const camera3_callback_ops_t *callback_ops); + int configureStreams(camera3_stream_configuration_t *stream_list); + const camera_metadata_t *constructDefaultRequestSettings(int type); + int processCaptureRequest(camera3_capture_request_t *request); + int flush(); + void dump(int fd); + + // Update static camera characteristics. This method could be called by + // HAL hotplug thread when camera is plugged. + void updateInfo(); + + protected: + // Initialize static camera characteristics. + virtual int initStaticInfo() = 0; + // Verify settings are valid for a capture + virtual bool isValidCaptureSettings(const camera_metadata_t *) = 0; + // Separate open method for individual devices + virtual int openDevice() = 0; + // Separate initialization method for individual devices when opened + virtual int initDevice() = 0; + // Flush camera pipeline for each individual device + virtual int flushDevice() = 0; + // Separate close method for individual devices + virtual int closeDevice() = 0; + // Capture and file an output buffer for an input buffer. + virtual int processCaptureBuffer(const camera3_stream_buffer_t *in, + camera3_stream_buffer_t *out) = 0; + // Accessor method used by initDevice() to set the templates' metadata + int setTemplate(int type, camera_metadata_t *settings); + // Prettyprint template names + const char* templateToString(int type); + // Process an output buffer + + // Identifier used by framework to distinguish cameras + const int mId; + // Metadata containing persistent camera characteristics + Metadata mMetadata; + // camera_metadata structure containing static characteristics + camera_metadata_t *mStaticInfo; + + private: + // Camera device handle returned to framework for use + camera3_device_t mDevice; + // Reuse a stream already created by this device. Must be called with mDeviceLock held. + Stream *reuseStreamLocked(camera3_stream_t *astream); + // Destroy all streams in a stream array, and the array itself. Must be called with + // mDeviceLock held. + void destroyStreamsLocked(android::Vector<Stream *> &streams); + // Verify a set of streams is valid in aggregate. Must be called with mDeviceLock held. + bool isValidStreamSetLocked(const android::Vector<Stream *> &streams); + // Calculate usage and max_bufs of each stream. Must be called with mDeviceLock held. + void setupStreamsLocked(android::Vector<Stream *> &streams); + // Update new settings for re-use and clean up old settings. Must be called with + // mDeviceLock held. + void updateSettingsLocked(const camera_metadata_t *new_settings); + // Send a shutter notify message with start of exposure time + void notifyShutter(uint32_t frame_number, uint64_t timestamp); + // Is type a valid template type (and valid index into mTemplates) + bool isValidTemplateType(int type); + + // Busy flag indicates camera is in use + bool mBusy; + // Camera device operations handle shared by all devices + const static camera3_device_ops_t sOps; + // Methods used to call back into the framework + const camera3_callback_ops_t *mCallbackOps; + // Lock protecting the Camera object for modifications + android::Mutex mDeviceLock; + // Lock protecting only static camera characteristics, which may + // be accessed without the camera device open + android::Mutex mStaticInfoLock; + // Array of handles to streams currently in use by the device + android::Vector<Stream *> mStreams; + // Static array of standard camera settings templates + camera_metadata_t *mTemplates[CAMERA3_TEMPLATE_COUNT]; + // Most recent request settings seen, memoized to be reused + camera_metadata_t *mSettings; + bool mIsInitialized; +}; +} // namespace usb_camera_hal + +#endif // CAMERA_H_ diff --git a/modules/usbcamera/CameraHAL.cpp b/modules/usbcamera/CameraHAL.cpp new file mode 100644 index 0000000..98111ef --- /dev/null +++ b/modules/usbcamera/CameraHAL.cpp @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2015 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_NDEBUG 0 +#define LOG_TAG "UsbCameraHAL" +#include <cutils/log.h> + +#include <cstdlib> +#include <hardware/camera_common.h> +#include <hardware/hardware.h> +#include "UsbCamera.h" +#include "CameraHAL.h" + +/* + * This file serves as the entry point to the HAL. It contains the module + * structure and functions used by the framework to load and interface to this + * HAL, as well as the handles to the individual camera devices. + */ + +namespace usb_camera_hal { + +static CameraHAL gCameraHAL; + +CameraHAL::CameraHAL() + : mCallbacks(NULL) { + // Should not allocate the camera devices for now, as it is unclear if the device is plugged. + + // Start hotplug thread + mHotplugThread = new HotplugThread(this); + mHotplugThread->run("usb-camera-hotplug"); +} + +CameraHAL::~CameraHAL() { + // Stop hotplug thread + { + android::Mutex::Autolock al(mModuleLock); + if (mHotplugThread != NULL) { + mHotplugThread->requestExit(); + } + + // Delete camera device from mCameras + } + + // Joining done without holding mLock, otherwise deadlocks may ensue + // as the threads try to access parent states. + if (mHotplugThread != NULL) { + mHotplugThread->join(); + } + + delete mHotplugThread; +} + +int CameraHAL::getNumberOfCameras() { + android::Mutex::Autolock al(mModuleLock); + ALOGV("%s: %d", __func__, mCameras.size()); + return static_cast<int>(mCameras.size()); +} + +int CameraHAL::getCameraInfo(int id, struct camera_info* info) { + android::Mutex::Autolock al(mModuleLock); + ALOGV("%s: camera id %d: info=%p", __func__, id, info); + if (id < 0 || id >= static_cast<int>(mCameras.size())) { + ALOGE("%s: Invalid camera id %d", __func__, id); + return -ENODEV; + } + + return mCameras[id]->getInfo(info); +} + +int CameraHAL::setCallbacks(const camera_module_callbacks_t *callbacks) { + ALOGV("%s : callbacks=%p", __func__, callbacks); + mCallbacks = callbacks; + return 0; +} + +int CameraHAL::open(const hw_module_t* mod, const char* name, hw_device_t** dev) { + int id; + char *nameEnd; + + android::Mutex::Autolock al(mModuleLock); + ALOGV("%s: module=%p, name=%s, device=%p", __func__, mod, name, dev); + if (*name == '\0') { + ALOGE("%s: Invalid camera id name is NULL", __func__); + return -EINVAL; + } + id = strtol(name, &nameEnd, 10); + if (*nameEnd != '\0') { + ALOGE("%s: Invalid camera id name %s", __func__, name); + return -EINVAL; + } else if (id < 0 || id >= static_cast<int>(mCameras.size())) { + ALOGE("%s: Invalid camera id %d", __func__, id); + return -ENODEV; + } + return mCameras[id]->open(mod, dev); +} + +extern "C" { + +static int get_number_of_cameras() { + return gCameraHAL.getNumberOfCameras(); +} + +static int get_camera_info(int id, struct camera_info* info) { + return gCameraHAL.getCameraInfo(id, info); +} + +static int set_callbacks(const camera_module_callbacks_t *callbacks) { + return gCameraHAL.setCallbacks(callbacks); +} + +static int open_dev(const hw_module_t* mod, const char* name, hw_device_t** dev) { + return gCameraHAL.open(mod, name, dev); +} + +static hw_module_methods_t gCameraModuleMethods = { + open : open_dev +}; + +camera_module_t HAL_MODULE_INFO_SYM __attribute__ ((visibility("default"))) = { + common : { + tag : HARDWARE_MODULE_TAG, + module_api_version : CAMERA_MODULE_API_VERSION_2_4, + hal_api_version : HARDWARE_HAL_API_VERSION, + id : CAMERA_HARDWARE_MODULE_ID, + name : "Default USB Camera HAL", + author : "The Android Open Source Project", + methods : &gCameraModuleMethods, + dso : NULL, + reserved : {0}, + }, + get_number_of_cameras : get_number_of_cameras, + get_camera_info : get_camera_info, + set_callbacks : set_callbacks, + get_vendor_tag_ops : NULL, + open_legacy : NULL, + set_torch_mode : NULL, + reserved : {0}, +}; +} // extern "C" + +} // namespace usb_camera_hal diff --git a/modules/usbcamera/CameraHAL.h b/modules/usbcamera/CameraHAL.h new file mode 100644 index 0000000..1770d95 --- /dev/null +++ b/modules/usbcamera/CameraHAL.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef CAMERA_HAL_H_ +#define CAMERA_HAL_H_ + +#include <hardware/hardware.h> +#include <hardware/camera_common.h> +#include <utils/Vector.h> +#include <utils/Mutex.h> +#include "HotplugThread.h" +#include "Camera.h" + +namespace usb_camera_hal { + +class HotplugThread; + +/** + * CameraHAL contains all module state that isn't specific to an individual camera device + */ +class CameraHAL { + public: + CameraHAL(); + ~CameraHAL(); + + // Camera Module Interface (see <hardware/camera_common.h>) + int getNumberOfCameras(); + int getCameraInfo(int camera_id, struct camera_info *info); + int setCallbacks(const camera_module_callbacks_t *callbacks); + void getVendorTagOps(vendor_tag_ops_t* ops); + + // Hardware Module Interface (see <hardware/hardware.h>) + int open(const hw_module_t* mod, const char* name, hw_device_t** dev); + + private: + // Callback handle + const camera_module_callbacks_t *mCallbacks; + android::Vector<Camera*> mCameras; + // Lock to protect the module method calls. + android::Mutex mModuleLock; + // Hot plug thread managing camera hot plug. + HotplugThread *mHotplugThread; + +}; +} // namespace usb_camera_hal + +#endif // CAMERA_HAL_H_ diff --git a/modules/usbcamera/HotplugThread.cpp b/modules/usbcamera/HotplugThread.cpp new file mode 100644 index 0000000..6c65086 --- /dev/null +++ b/modules/usbcamera/HotplugThread.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2015 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_NDEBUG 0 +#define LOG_TAG "HotplugThread" +#include <cutils/log.h> + +#include "HotplugThread.h" + +namespace usb_camera_hal { + +HotplugThread::HotplugThread(CameraHAL *hal) + : mModule(hal) { + +} + +HotplugThread::~HotplugThread() { + +} + +void HotplugThread::requestExit() { + // Call parent to set up shutdown + Thread::requestExit(); + + // Cleanup other states? +} + +bool HotplugThread::threadLoop() { + + /** + * Check camera connection status change, if connected, do below: + * 1. Create camera device, add to mCameras. + * 2. Init static info (mCameras[id]->initStaticInfo()) + * 3. Notify on_status_change callback + * + * If unconnected, similarly, do below: + * 1. Destroy camera device and remove it from mCameras. + * 2. Notify on_status_change callback + * + * DO NOT have a tight polling loop here, to avoid excessive CPU utilization. + */ + + return true; +} + +} // namespace usb_camera_hal diff --git a/modules/usbcamera/HotplugThread.h b/modules/usbcamera/HotplugThread.h new file mode 100644 index 0000000..a13adb7 --- /dev/null +++ b/modules/usbcamera/HotplugThread.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2015 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. + */ +#ifndef HOTPLUG_THREAD_H_ +#define HOTPLUG_THREAD_H_ + +#include <utils/Thread.h> +#include "CameraHAL.h" + +namespace usb_camera_hal { +/** + * Thread for managing usb camera hotplug. It does below: + * 1. Monitor camera hotplug status, and notify the status changes by calling + * module callback methods. + * 2. When camera is plugged, create camera device instance, initialize the camera + * static info. When camera is unplugged, destroy the camera device instance and + * static metadata. As an optimization option, the camera device instance (including + * the static info) could be cached when the same camera plugged/unplugged multiple + * times. + */ + +class CameraHAL; + +class HotplugThread : public android::Thread { + + public: + HotplugThread(CameraHAL *hal); + ~HotplugThread(); + + // Override below two methods for proper cleanup. + virtual bool threadLoop(); + virtual void requestExit(); + + private: + CameraHAL *mModule; +}; + +} // namespace usb_camera_hal + +#endif // HOTPLUG_THREAD_H_ diff --git a/modules/usbcamera/Metadata.cpp b/modules/usbcamera/Metadata.cpp new file mode 100644 index 0000000..f243834 --- /dev/null +++ b/modules/usbcamera/Metadata.cpp @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2015 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_NDEBUG 0 +#define LOG_TAG "Metadata" +#include <cutils/log.h> + +#include <system/camera_metadata.h> + +#define ATRACE_TAG (ATRACE_TAG_CAMERA | ATRACE_TAG_HAL) +#include <utils/Trace.h> + +#include "Metadata.h" + +namespace usb_camera_hal { + +Metadata::Metadata(): + mData(NULL) { +} + +Metadata::~Metadata() { + replace(NULL); +} + +void Metadata::replace(camera_metadata_t *m) { + if (m == mData) { + return; + } + if (mData) + free_camera_metadata(mData); + mData = m; +} + +int Metadata::init(const camera_metadata_t *metadata) { + camera_metadata_t* tmp; + + if (!validate_camera_metadata_structure(metadata, NULL)) + return -EINVAL; + + tmp = clone_camera_metadata(metadata); + if (tmp == NULL) + return -EINVAL; + + replace(tmp); + return 0; +} + +int Metadata::addUInt8(uint32_t tag, int count, const uint8_t *data) { + if (!validate(tag, TYPE_BYTE, count)) return -EINVAL; + return add(tag, count, data); +} + +int Metadata::add1UInt8(uint32_t tag, const uint8_t data) { + return addUInt8(tag, 1, &data); +} + +int Metadata::addInt32(uint32_t tag, int count, const int32_t *data) { + if (!validate(tag, TYPE_INT32, count)) return -EINVAL; + return add(tag, count, data); +} + +int Metadata::addFloat(uint32_t tag, int count, const float *data) { + if (!validate(tag, TYPE_FLOAT, count)) return -EINVAL; + return add(tag, count, data); +} + +int Metadata::addInt64(uint32_t tag, int count, const int64_t *data) { + if (!validate(tag, TYPE_INT64, count)) return -EINVAL; + return add(tag, count, data); +} + +int Metadata::addDouble(uint32_t tag, int count, const double *data) { + if (!validate(tag, TYPE_DOUBLE, count)) return -EINVAL; + return add(tag, count, data); +} + +int Metadata::addRational(uint32_t tag, int count, + const camera_metadata_rational_t *data) { + if (!validate(tag, TYPE_RATIONAL, count)) return -EINVAL; + return add(tag, count, data); +} + +bool Metadata::validate(uint32_t tag, int tag_type, int count) { + if (get_camera_metadata_tag_type(tag) < 0) { + ALOGE("%s: Invalid metadata entry tag: %d", __func__, tag); + return false; + } + if (tag_type < 0 || tag_type >= NUM_TYPES) { + ALOGE("%s: Invalid metadata entry tag type: %d", __func__, tag_type); + return false; + } + if (tag_type != get_camera_metadata_tag_type(tag)) { + ALOGE("%s: Tag %d called with incorrect type: %s(%d)", __func__, tag, + camera_metadata_type_names[tag_type], tag_type); + return false; + } + if (count < 1) { + ALOGE("%s: Invalid metadata entry count: %d", __func__, count); + return false; + } + return true; +} + +int Metadata::add(uint32_t tag, int count, const void *tag_data) { + // Opportunistically attempt to add if metadata has room for it + if (!add_camera_metadata_entry(mData, tag, tag_data, count)) { + return 0; + } + + int res; + camera_metadata_t* tmp; + int tag_type = get_camera_metadata_tag_type(tag); + size_t size = calculate_camera_metadata_entry_data_size(tag_type, count); + size_t entry_capacity = get_camera_metadata_entry_count(mData) + 1; + size_t data_capacity = get_camera_metadata_data_count(mData) + size; + + // Double new dimensions to minimize future reallocations + tmp = allocate_camera_metadata(entry_capacity * 2, data_capacity * 2); + if (tmp == NULL) { + ALOGE("%s: Failed to allocate new metadata with %zu entries, %zu data", + __func__, entry_capacity, data_capacity); + return -ENOMEM; + } + // Append the current metadata to the new (empty) metadata + res = append_camera_metadata(tmp, mData); + if (res) { + ALOGE("%s: Failed to append old metadata %p to new %p", + __func__, mData, tmp); + return res; + } + // Add the remaining new item + res = add_camera_metadata_entry(tmp, tag, tag_data, count); + if (res) { + ALOGE("%s: Failed to add new entry (%d, %p, %d) to metadata %p", + __func__, tag, tag_data, count, tmp); + return res; + } + + replace(tmp); + return 0; +} + +camera_metadata_t* Metadata::get() { + return mData; +} + +} // namespace usb_camera_hal diff --git a/modules/usbcamera/Metadata.h b/modules/usbcamera/Metadata.h new file mode 100644 index 0000000..288db16 --- /dev/null +++ b/modules/usbcamera/Metadata.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef METADATA_H_ +#define METADATA_H_ + +#include <stdint.h> +#include <hardware/camera3.h> +#include <system/camera_metadata.h> + +namespace usb_camera_hal { +// Metadata is a convenience class for dealing with libcamera_metadata +class Metadata { + public: + Metadata(); + ~Metadata(); + // Initialize with framework metadata + int init(const camera_metadata_t *metadata); + + // Parse and add an entry. Allocates and copies new storage for *data. + int addUInt8(uint32_t tag, int count, const uint8_t *data); + int add1UInt8(uint32_t tag, const uint8_t data); + int addInt32(uint32_t tag, int count, const int32_t *data); + int addFloat(uint32_t tag, int count, const float *data); + int addInt64(uint32_t tag, int count, const int64_t *data); + int addDouble(uint32_t tag, int count, const double *data); + int addRational(uint32_t tag, int count, + const camera_metadata_rational_t *data); + + // Get a handle to the current metadata + // This is not a durable handle, and may be destroyed by add*/init + camera_metadata_t* get(); + + private: + // Actual internal storage + camera_metadata_t* mData; + // Destroy old metadata and replace with new + void replace(camera_metadata_t *m); + // Validate the tag, type and count for a metadata entry + bool validate(uint32_t tag, int tag_type, int count); + // Add a verified tag with data + int add(uint32_t tag, int count, const void *tag_data); +}; +} // namespace usb_camera_hal + +#endif // METADATA_H_ diff --git a/modules/usbcamera/Stream.cpp b/modules/usbcamera/Stream.cpp new file mode 100644 index 0000000..a3fefa3 --- /dev/null +++ b/modules/usbcamera/Stream.cpp @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2015 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_NDEBUG 0 +#define LOG_TAG "Stream" +#include <cutils/log.h> + +#include <stdio.h> +#include <hardware/camera3.h> +#include <hardware/gralloc.h> +#include <system/graphics.h> +#include <utils/Mutex.h> + +#define ATRACE_TAG (ATRACE_TAG_CAMERA | ATRACE_TAG_HAL) +#include <utils/Trace.h> + +#include "Stream.h" + +namespace usb_camera_hal { + +Stream::Stream(int id, camera3_stream_t *s) + : mReuse(false), + mId(id), + mStream(s){ +} + +Stream::~Stream() { + for (size_t i = 0; i < mBuffers.size(); i++) { + delete mBuffers[i]; + } + + mBuffers.clear(); +} + +void Stream::setUsage(uint32_t usage) { + android::Mutex::Autolock al(mLock); + if (usage != mStream->usage) { + mStream->usage = usage; + } +} + +void Stream::setMaxBuffers(uint32_t max_buffers) { + android::Mutex::Autolock al(mLock); + if (max_buffers != mStream->max_buffers) { + mStream->max_buffers = max_buffers; + } +} + +int Stream::getType() { + return mStream->stream_type; +} + +bool Stream::isInputType() { + return mStream->stream_type == CAMERA3_STREAM_INPUT || + mStream->stream_type == CAMERA3_STREAM_BIDIRECTIONAL; +} + +bool Stream::isOutputType() { + return mStream->stream_type == CAMERA3_STREAM_OUTPUT || + mStream->stream_type == CAMERA3_STREAM_BIDIRECTIONAL; +} + +const char* Stream::typeToString(int type) { + switch (type) { + case CAMERA3_STREAM_INPUT: + return "CAMERA3_STREAM_INPUT"; + case CAMERA3_STREAM_OUTPUT: + return "CAMERA3_STREAM_OUTPUT"; + case CAMERA3_STREAM_BIDIRECTIONAL: + return "CAMERA3_STREAM_BIDIRECTIONAL"; + } + return "Invalid stream type!"; +} + +const char* Stream::formatToString(int format) { + // See <system/graphics.h> for full list + switch (format) { + case HAL_PIXEL_FORMAT_BGRA_8888: + return "BGRA 8888"; + case HAL_PIXEL_FORMAT_RGBA_8888: + return "RGBA 8888"; + case HAL_PIXEL_FORMAT_RGBX_8888: + return "RGBX 8888"; + case HAL_PIXEL_FORMAT_RGB_888: + return "RGB 888"; + case HAL_PIXEL_FORMAT_RGB_565: + return "RGB 565"; + case HAL_PIXEL_FORMAT_sRGB_A_8888: + return "sRGB A 8888"; + case HAL_PIXEL_FORMAT_sRGB_X_8888: + return "sRGB B 8888"; + case HAL_PIXEL_FORMAT_Y8: + return "Y8"; + case HAL_PIXEL_FORMAT_Y16: + return "Y16"; + case HAL_PIXEL_FORMAT_YV12: + return "YV12"; + case HAL_PIXEL_FORMAT_YCbCr_422_SP: + return "NV16"; + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + return "NV21"; + case HAL_PIXEL_FORMAT_YCbCr_422_I: + return "YUY2"; + case HAL_PIXEL_FORMAT_RAW_SENSOR: + return "RAW SENSOR"; + case HAL_PIXEL_FORMAT_BLOB: + return "BLOB"; + case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: + return "IMPLEMENTATION DEFINED"; + case HAL_PIXEL_FORMAT_YCbCr_420_888: + return "FLEXIBLE YCbCr 420 888"; + } + return "Invalid stream format!"; +} + +bool Stream::isValidReuseStream(int id, camera3_stream_t *s) { + if (id != mId) { + ALOGE("%s:%d: Invalid camera id for reuse. Got %d expect %d", + __func__, mId, id, mId); + return false; + } + if (s != mStream) { + ALOGE("%s:%d: Invalid stream handle for reuse. Got %p expect %p", + __func__, mId, s, mStream); + return false; + } + if (s->stream_type != mStream->stream_type) { + ALOGE("%s:%d: Mismatched type in reused stream. Got %s(%d) " + "expect %s(%d)", __func__, mId, typeToString(s->stream_type), + s->stream_type, typeToString(mStream->stream_type), mStream->stream_type); + return false; + } + if (s->format != mStream->format) { + ALOGE("%s:%d: Mismatched format in reused stream. Got %s(%d) " + "expect %s(%d)", __func__, mId, formatToString(s->format), + s->format, formatToString(mStream->format), mStream->format); + return false; + } + if (s->width != mStream->width) { + ALOGE("%s:%d: Mismatched width in reused stream. Got %d expect %d", + __func__, mId, s->width, mStream->width); + return false; + } + if (s->height != mStream->height) { + ALOGE("%s:%d: Mismatched height in reused stream. Got %d expect %d", + __func__, mId, s->height, mStream->height); + return false; + } + return true; +} + +void Stream::dump(int fd) { + android::Mutex::Autolock al(mLock); + + dprintf(fd, "Stream ID: %d (%p)\n", mId, mStream); + dprintf(fd, "Stream Type: %s (%d)\n", typeToString(mStream->stream_type), mStream->stream_type); + dprintf(fd, "Width: %" PRIu32 " Height: %" PRIu32 "\n", mStream->width, mStream->height); + dprintf(fd, "Stream Format: %s (%d)", formatToString(mStream->format), mStream->format); + // ToDo: prettyprint usage mask flags + dprintf(fd, "Gralloc Usage Mask: %#" PRIx32 "\n", mStream->usage); + dprintf(fd, "Max Buffer Count: %" PRIu32 "\n", mStream->max_buffers); + dprintf(fd, "Number of Buffers in use by HAL: %" PRIu32 "\n", mBuffers.size()); + for (size_t i = 0; i < mBuffers.size(); i++) { + dprintf(fd, "Buffer %" PRIu32 "/%" PRIu32 ": %p\n", i, mBuffers.size(), + mBuffers[i]); + } +} + +} // namespace usb_camera_hal diff --git a/modules/usbcamera/Stream.h b/modules/usbcamera/Stream.h new file mode 100644 index 0000000..022ca9f --- /dev/null +++ b/modules/usbcamera/Stream.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef STREAM_H_ +#define STREAM_H_ + +#include <hardware/camera3.h> +#include <hardware/gralloc.h> +#include <system/graphics.h> +#include <utils/Mutex.h> +#include <utils/Vector.h> + +namespace usb_camera_hal { +// Stream represents a single input or output stream for a camera device. +class Stream { + public: + Stream(int id, camera3_stream_t *s); + ~Stream(); + + // validate that a stream's parameters match this stream's parameters + bool isValidReuseStream(int id, camera3_stream_t *s); + + void setUsage(uint32_t usage); + void setMaxBuffers(uint32_t max_buffers); + + int getType(); + bool isInputType(); + bool isOutputType(); + const char* typeToString(int type); + const char* formatToString(int format); + void dump(int fd); + + // This stream is being reused. Used in stream configuration passes + bool mReuse; + + private: + // The camera device id this stream belongs to + const int mId; + // Handle to framework's stream, used as a cookie for buffers + camera3_stream_t *mStream; + // Array of handles to buffers currently in use by the stream + android::Vector<buffer_handle_t *> mBuffers; + // Lock protecting the Stream object for modifications + android::Mutex mLock; +}; +} // namespace usb_camera_hal + +#endif // STREAM_H_ diff --git a/modules/usbcamera/UsbCamera.cpp b/modules/usbcamera/UsbCamera.cpp new file mode 100644 index 0000000..ded3e92 --- /dev/null +++ b/modules/usbcamera/UsbCamera.cpp @@ -0,0 +1,321 @@ +/* + * Copyright (C) 2015 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_NDEBUG 0 +#define LOG_TAG "UsbCameraDevice" +#include <cutils/log.h> + +#include <system/camera_metadata.h> + +#define ATRACE_TAG (ATRACE_TAG_CAMERA | ATRACE_TAG_HAL) +#include <utils/Trace.h> + +#include "Camera.h" +#include "UsbCamera.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +namespace usb_camera_hal { + +UsbCamera::UsbCamera(int id) : Camera(id) { +} + +UsbCamera::~UsbCamera() { +} + +int UsbCamera::initStaticInfo() { + /* + * Setup static camera info. This will have to customized per camera + * device. + * TODO: this is just some sample code, need tailor for USB cameras. + */ + if (mStaticInfo != NULL) { + free_camera_metadata(mStaticInfo); + } + + Metadata m; + + /* android.control */ + int32_t android_control_ae_available_target_fps_ranges[] = {30, 30}; + m.addInt32(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, + ARRAY_SIZE(android_control_ae_available_target_fps_ranges), + android_control_ae_available_target_fps_ranges); + + int32_t android_control_ae_compensation_range[] = {-4, 4}; + m.addInt32(ANDROID_CONTROL_AE_COMPENSATION_RANGE, + ARRAY_SIZE(android_control_ae_compensation_range), + android_control_ae_compensation_range); + + camera_metadata_rational_t android_control_ae_compensation_step[] = {{2,1}}; + m.addRational(ANDROID_CONTROL_AE_COMPENSATION_STEP, + ARRAY_SIZE(android_control_ae_compensation_step), + android_control_ae_compensation_step); + + int32_t android_control_max_regions[] = {/*AE*/ 1,/*AWB*/ 1,/*AF*/ 1}; + m.addInt32(ANDROID_CONTROL_MAX_REGIONS, + ARRAY_SIZE(android_control_max_regions), + android_control_max_regions); + + /* android.jpeg */ + int32_t android_jpeg_available_thumbnail_sizes[] = {0, 0, 128, 96}; + m.addInt32(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES, + ARRAY_SIZE(android_jpeg_available_thumbnail_sizes), + android_jpeg_available_thumbnail_sizes); + + int32_t android_jpeg_max_size[] = {13 * 1024 * 1024}; // 13MB + m.addInt32(ANDROID_JPEG_MAX_SIZE, + ARRAY_SIZE(android_jpeg_max_size), + android_jpeg_max_size); + + /* android.lens */ + float android_lens_info_available_focal_lengths[] = {1.0}; + m.addFloat(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS, + ARRAY_SIZE(android_lens_info_available_focal_lengths), + android_lens_info_available_focal_lengths); + + /* android.request */ + int32_t android_request_max_num_output_streams[] = {0, 3, 1}; + m.addInt32(ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS, + ARRAY_SIZE(android_request_max_num_output_streams), + android_request_max_num_output_streams); + + /* android.scaler */ + int32_t android_scaler_available_formats[] = { + HAL_PIXEL_FORMAT_RAW_SENSOR, + HAL_PIXEL_FORMAT_BLOB, + HAL_PIXEL_FORMAT_RGBA_8888, + HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, + // These are handled by YCbCr_420_888 + // HAL_PIXEL_FORMAT_YV12, + // HAL_PIXEL_FORMAT_YCrCb_420_SP, + HAL_PIXEL_FORMAT_YCbCr_420_888}; + m.addInt32(ANDROID_SCALER_AVAILABLE_FORMATS, + ARRAY_SIZE(android_scaler_available_formats), + android_scaler_available_formats); + + int64_t android_scaler_available_jpeg_min_durations[] = {1}; + m.addInt64(ANDROID_SCALER_AVAILABLE_JPEG_MIN_DURATIONS, + ARRAY_SIZE(android_scaler_available_jpeg_min_durations), + android_scaler_available_jpeg_min_durations); + + int32_t android_scaler_available_jpeg_sizes[] = {640, 480}; + m.addInt32(ANDROID_SCALER_AVAILABLE_JPEG_SIZES, + ARRAY_SIZE(android_scaler_available_jpeg_sizes), + android_scaler_available_jpeg_sizes); + + float android_scaler_available_max_digital_zoom[] = {1}; + m.addFloat(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM, + ARRAY_SIZE(android_scaler_available_max_digital_zoom), + android_scaler_available_max_digital_zoom); + + int64_t android_scaler_available_processed_min_durations[] = {1}; + m.addInt64(ANDROID_SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS, + ARRAY_SIZE(android_scaler_available_processed_min_durations), + android_scaler_available_processed_min_durations); + + int32_t android_scaler_available_processed_sizes[] = {640, 480}; + m.addInt32(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES, + ARRAY_SIZE(android_scaler_available_processed_sizes), + android_scaler_available_processed_sizes); + + int64_t android_scaler_available_raw_min_durations[] = {1}; + m.addInt64(ANDROID_SCALER_AVAILABLE_RAW_MIN_DURATIONS, + ARRAY_SIZE(android_scaler_available_raw_min_durations), + android_scaler_available_raw_min_durations); + + int32_t android_scaler_available_raw_sizes[] = {640, 480}; + m.addInt32(ANDROID_SCALER_AVAILABLE_RAW_SIZES, + ARRAY_SIZE(android_scaler_available_raw_sizes), + android_scaler_available_raw_sizes); + + /* android.sensor */ + + int32_t android_sensor_info_active_array_size[] = {0, 0, 640, 480}; + m.addInt32(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE, + ARRAY_SIZE(android_sensor_info_active_array_size), + android_sensor_info_active_array_size); + + int32_t android_sensor_info_sensitivity_range[] = + {100, 1600}; + m.addInt32(ANDROID_SENSOR_INFO_SENSITIVITY_RANGE, + ARRAY_SIZE(android_sensor_info_sensitivity_range), + android_sensor_info_sensitivity_range); + + int64_t android_sensor_info_max_frame_duration[] = {30000000000}; + m.addInt64(ANDROID_SENSOR_INFO_MAX_FRAME_DURATION, + ARRAY_SIZE(android_sensor_info_max_frame_duration), + android_sensor_info_max_frame_duration); + + float android_sensor_info_physical_size[] = {3.2, 2.4}; + m.addFloat(ANDROID_SENSOR_INFO_PHYSICAL_SIZE, + ARRAY_SIZE(android_sensor_info_physical_size), + android_sensor_info_physical_size); + + int32_t android_sensor_info_pixel_array_size[] = {640, 480}; + m.addInt32(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE, + ARRAY_SIZE(android_sensor_info_pixel_array_size), + android_sensor_info_pixel_array_size); + + int32_t android_sensor_orientation[] = {0}; + m.addInt32(ANDROID_SENSOR_ORIENTATION, + ARRAY_SIZE(android_sensor_orientation), + android_sensor_orientation); + + /* End of static camera characteristics */ + + mStaticInfo = clone_camera_metadata(m.get()); + + return 0; +} + +int UsbCamera::openDevice() { + // TODO: implement usb camera device open sequence: open device nodes etc. + + return 0; +} + +int UsbCamera::closeDevice() { + // TODO: implement usb camera device close sequence: close device nodes etc. + + return 0; +} + +int UsbCamera::processCaptureBuffer(const camera3_stream_buffer_t *in, + camera3_stream_buffer_t *out) { + if (in->acquire_fence != -1) { + int res = sync_wait(in->acquire_fence, CAMERA_SYNC_TIMEOUT_MS); + if (res == -ETIME) { + ALOGE("%s:%d: Timeout waiting on buffer acquire fence", + __func__, mId); + return res; + } else if (res) { + ALOGE("%s:%d: Error waiting on buffer acquire fence: %s(%d)", + __func__, mId, strerror(-res), res); + return res; + } + } + + out->stream = in->stream; + out->buffer = in->buffer; + out->status = CAMERA3_BUFFER_STATUS_OK; + // TODO: use driver-backed release fences + out->acquire_fence = -1; + out->release_fence = -1; + + // TODO: lock and software-paint buffer + return 0; +} + +int UsbCamera::initDevice() { + int res; + Metadata base; + + // Create standard settings templates from copies of base metadata + res = base.add1UInt8(ANDROID_CONTROL_MODE, ANDROID_CONTROL_MODE_OFF); + if (res) + return res; + + // Use base settings to create all other templates and set them. This is just some samples, + // More initialization may be needed. + res = initPreviewTemplate(base); + if (res) + return res; + res = initStillTemplate(base); + if (res) + return res; + res = initRecordTemplate(base); + if (res) + return res; + res = initSnapshotTemplate(base); + if (res) + return res; + res = initZslTemplate(base); + if (res) + return res; + res = initManualTemplate(base); + if (res) + return res; + + return 0; +} + +int UsbCamera::initPreviewTemplate(Metadata m) { + // Setup default preview controls + int res = m.add1UInt8(ANDROID_CONTROL_CAPTURE_INTENT, + ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW); + + if (res) + return res; + // TODO: set fast auto-focus, auto-whitebalance, auto-exposure, auto flash + return setTemplate(CAMERA3_TEMPLATE_PREVIEW, m.get()); +} + +int UsbCamera::initStillTemplate(Metadata m) { + int res = m.add1UInt8(ANDROID_CONTROL_CAPTURE_INTENT, + ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE); + // Setup default still capture controls + if (res) + return res; + // TODO: set fast auto-focus, auto-whitebalance, auto-exposure, auto flash + return setTemplate(CAMERA3_TEMPLATE_STILL_CAPTURE, m.get()); +} + +int UsbCamera::initRecordTemplate(Metadata m) { + int res = m.add1UInt8(ANDROID_CONTROL_CAPTURE_INTENT, + ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD); + // Setup default video record controls + if (res) + return res; + // TODO: set slow auto-focus, auto-whitebalance, auto-exposure, flash off + return setTemplate(CAMERA3_TEMPLATE_VIDEO_RECORD, m.get()); +} + +int UsbCamera::initSnapshotTemplate(Metadata m) { + int res = m.add1UInt8(ANDROID_CONTROL_CAPTURE_INTENT, + ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT); + // Setup default video snapshot controls + if (res) + return res; + // TODO: set slow auto-focus, auto-whitebalance, auto-exposure, flash off + return setTemplate(CAMERA3_TEMPLATE_VIDEO_SNAPSHOT, m.get()); +} + +int UsbCamera::initZslTemplate(Metadata m) { + int res = m.add1UInt8(ANDROID_CONTROL_CAPTURE_INTENT, + ANDROID_CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG); + // Setup default zero shutter lag controls + if (res) + return res; + // TODO: set reprocessing parameters for zsl input queue + return setTemplate(CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG, m.get()); +} + +int UsbCamera::initManualTemplate(Metadata m) { + int res = m.add1UInt8(ANDROID_CONTROL_CAPTURE_INTENT, + ANDROID_CONTROL_CAPTURE_INTENT_MANUAL); + // Setup manual controls + if (res) + return res; + // TODO: set reprocessing parameters for zsl input queue + return setTemplate(CAMERA3_TEMPLATE_MANUAL, m.get()); +} + +bool UsbCamera::isValidCaptureSettings(const camera_metadata_t* settings) { + // TODO: reject settings that cannot be captured + return true; +} + +} // namespace usb_camera_hal diff --git a/modules/usbcamera/UsbCamera.h b/modules/usbcamera/UsbCamera.h new file mode 100644 index 0000000..fe52ade --- /dev/null +++ b/modules/usbcamera/UsbCamera.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef EXAMPLE_CAMERA_H_ +#define EXAMPLE_CAMERA_H_ + +#include <system/camera_metadata.h> +#include "Camera.h" + +namespace usb_camera_hal { +/** + * UsbCamera is an example for a specific camera device. The Camera instance contains + * a specific camera device (e.g. UsbCamera) holds all specific metadata and logic about + * that device. + */ +class UsbCamera : public Camera { + public: + UsbCamera(int id); + ~UsbCamera(); + + private: + // Initialize static camera characteristics for individual device + int initStaticInfo(); + int openDevice(); + // Initialize whole device (templates/etc) when opened + int initDevice(); + int flushDevice(); + int closeDevice(); + int processCaptureBuffer(const camera3_stream_buffer_t *in, camera3_stream_buffer_t *out); + // Initialize each template metadata controls + int initPreviewTemplate(Metadata m); + int initStillTemplate(Metadata m); + int initRecordTemplate(Metadata m); + int initSnapshotTemplate(Metadata m); + int initZslTemplate(Metadata m); + int initManualTemplate(Metadata m); + // Verify settings are valid for a capture with this device + bool isValidCaptureSettings(const camera_metadata_t* settings); +}; +} // namespace usb_camera_hal + +#endif // CAMERA_H_ |