|
|
@ -2,6 +2,7 @@ |
|
|
|
* Copyright (C) 2013 The Android Open Source Project |
|
|
|
* Copyright (C) 2013 The Android Open Source Project |
|
|
|
* Copyright (C) 2017 Christopher N. Hesse <raymanfx@gmail.com> |
|
|
|
* Copyright (C) 2017 Christopher N. Hesse <raymanfx@gmail.com> |
|
|
|
* Copyright (C) 2017 Andreas Schneider <asn@cryptomilk.org> |
|
|
|
* Copyright (C) 2017 Andreas Schneider <asn@cryptomilk.org> |
|
|
|
|
|
|
|
* Copyright (C) 2018 The LineageOS Project |
|
|
|
* |
|
|
|
* |
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
|
|
* you may not use this file except in compliance with the License. |
|
|
|
* you may not use this file except in compliance with the License. |
|
|
@ -186,26 +187,6 @@ static struct pcm_device_profile pcm_device_capture_sco = { |
|
|
|
.devices = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, |
|
|
|
.devices = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
#ifdef SOUND_CAPTURE_HOTWORD_DEVICE |
|
|
|
|
|
|
|
static struct pcm_device_profile pcm_device_hotword_streaming = { |
|
|
|
|
|
|
|
.config = { |
|
|
|
|
|
|
|
.channels = 1, |
|
|
|
|
|
|
|
.rate = 16000, |
|
|
|
|
|
|
|
.period_size = CAPTURE_PERIOD_SIZE, |
|
|
|
|
|
|
|
.period_count = CAPTURE_PERIOD_COUNT, |
|
|
|
|
|
|
|
.format = PCM_FORMAT_S16_LE, |
|
|
|
|
|
|
|
.start_threshold = CAPTURE_START_THRESHOLD, |
|
|
|
|
|
|
|
.stop_threshold = 0, |
|
|
|
|
|
|
|
.silence_threshold = 0, |
|
|
|
|
|
|
|
.avail_min = 0, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
.card = SOUND_CARD, |
|
|
|
|
|
|
|
.id = SOUND_CAPTURE_HOTWORD_DEVICE, |
|
|
|
|
|
|
|
.type = PCM_HOTWORD_STREAMING, |
|
|
|
|
|
|
|
.devices = AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_WIRED_HEADSET|AUDIO_DEVICE_IN_BACK_MIC |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static struct pcm_device_profile * const pcm_devices[] = { |
|
|
|
static struct pcm_device_profile * const pcm_devices[] = { |
|
|
|
&pcm_device_playback, |
|
|
|
&pcm_device_playback, |
|
|
|
&pcm_device_capture, |
|
|
|
&pcm_device_capture, |
|
|
@ -214,9 +195,6 @@ static struct pcm_device_profile * const pcm_devices[] = { |
|
|
|
&pcm_device_capture_sco, |
|
|
|
&pcm_device_capture_sco, |
|
|
|
#ifdef SOUND_CAPTURE_LOOPBACK_AEC_DEVICE |
|
|
|
#ifdef SOUND_CAPTURE_LOOPBACK_AEC_DEVICE |
|
|
|
&pcm_device_capture_loopback_aec, |
|
|
|
&pcm_device_capture_loopback_aec, |
|
|
|
#endif |
|
|
|
|
|
|
|
#ifdef SOUND_CAPTURE_HOTWORD_DEVICE |
|
|
|
|
|
|
|
&pcm_device_hotword_streaming, |
|
|
|
|
|
|
|
#endif |
|
|
|
#endif |
|
|
|
NULL, |
|
|
|
NULL, |
|
|
|
}; |
|
|
|
}; |
|
|
@ -227,7 +205,6 @@ static const char * const use_case_table[AUDIO_USECASE_MAX] = { |
|
|
|
[USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback", |
|
|
|
[USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback", |
|
|
|
[USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = "playback deep-buffer", |
|
|
|
[USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = "playback deep-buffer", |
|
|
|
[USECASE_AUDIO_CAPTURE] = "capture", |
|
|
|
[USECASE_AUDIO_CAPTURE] = "capture", |
|
|
|
[USECASE_AUDIO_CAPTURE_HOTWORD] = "capture-hotword", |
|
|
|
|
|
|
|
[USECASE_VOICE_CALL] = "voice-call", |
|
|
|
[USECASE_VOICE_CALL] = "voice-call", |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
@ -1040,9 +1017,6 @@ static int select_devices(struct audio_device *adev, |
|
|
|
|
|
|
|
|
|
|
|
ALOGV("%s: usecase(%d)", __func__, uc_id); |
|
|
|
ALOGV("%s: usecase(%d)", __func__, uc_id); |
|
|
|
|
|
|
|
|
|
|
|
if (uc_id == USECASE_AUDIO_CAPTURE_HOTWORD) |
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
usecase = get_usecase_from_type(adev, PCM_CAPTURE|VOICE_CALL); |
|
|
|
usecase = get_usecase_from_type(adev, PCM_CAPTURE|VOICE_CALL); |
|
|
|
if (usecase != NULL) { |
|
|
|
if (usecase != NULL) { |
|
|
|
active_input = (struct stream_in *)usecase->stream; |
|
|
|
active_input = (struct stream_in *)usecase->stream; |
|
|
@ -2297,22 +2271,6 @@ static int start_input_stream(struct stream_in *in) |
|
|
|
pcm_device->pcm_profile->config.channels,pcm_device->pcm_profile->config.rate, |
|
|
|
pcm_device->pcm_profile->config.channels,pcm_device->pcm_profile->config.rate, |
|
|
|
pcm_device->pcm_profile->config.format, pcm_device->pcm_profile->config.period_size); |
|
|
|
pcm_device->pcm_profile->config.format, pcm_device->pcm_profile->config.period_size); |
|
|
|
|
|
|
|
|
|
|
|
if (pcm_profile->type == PCM_HOTWORD_STREAMING) { |
|
|
|
|
|
|
|
if (!adev->sound_trigger_open_for_streaming) { |
|
|
|
|
|
|
|
ALOGE("%s: No handle to sound trigger HAL", __func__); |
|
|
|
|
|
|
|
ret = -EIO; |
|
|
|
|
|
|
|
goto error_open; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
pcm_device->pcm = NULL; |
|
|
|
|
|
|
|
pcm_device->sound_trigger_handle = adev->sound_trigger_open_for_streaming(); |
|
|
|
|
|
|
|
if (pcm_device->sound_trigger_handle <= 0) { |
|
|
|
|
|
|
|
ALOGE("%s: Failed to open DSP for streaming", __func__); |
|
|
|
|
|
|
|
ret = -EIO; |
|
|
|
|
|
|
|
goto error_open; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
ALOGV("Opened DSP successfully"); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
pcm_device->sound_trigger_handle = 0; |
|
|
|
|
|
|
|
pcm_device->pcm = pcm_open(pcm_device->pcm_profile->card, pcm_device->pcm_profile->id, |
|
|
|
pcm_device->pcm = pcm_open(pcm_device->pcm_profile->card, pcm_device->pcm_profile->id, |
|
|
|
PCM_IN | PCM_MONOTONIC, &pcm_device->pcm_profile->config); |
|
|
|
PCM_IN | PCM_MONOTONIC, &pcm_device->pcm_profile->config); |
|
|
|
|
|
|
|
|
|
|
@ -2323,7 +2281,6 @@ static int start_input_stream(struct stream_in *in) |
|
|
|
ret = -EIO; |
|
|
|
ret = -EIO; |
|
|
|
goto error_open; |
|
|
|
goto error_open; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
skip_pcm_handling: |
|
|
|
skip_pcm_handling: |
|
|
|
/* force read and proc buffer reallocation in case of frame size or
|
|
|
|
/* force read and proc buffer reallocation in case of frame size or
|
|
|
@ -2419,14 +2376,9 @@ static int out_close_pcm_devices(struct stream_out *out) |
|
|
|
{ |
|
|
|
{ |
|
|
|
struct pcm_device *pcm_device; |
|
|
|
struct pcm_device *pcm_device; |
|
|
|
struct listnode *node; |
|
|
|
struct listnode *node; |
|
|
|
struct audio_device *adev = out->dev; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
list_for_each(node, &out->pcm_dev_list) { |
|
|
|
list_for_each(node, &out->pcm_dev_list) { |
|
|
|
pcm_device = node_to_item(node, struct pcm_device, stream_list_node); |
|
|
|
pcm_device = node_to_item(node, struct pcm_device, stream_list_node); |
|
|
|
if (pcm_device->sound_trigger_handle > 0) { |
|
|
|
|
|
|
|
adev->sound_trigger_close_for_streaming(pcm_device->sound_trigger_handle); |
|
|
|
|
|
|
|
pcm_device->sound_trigger_handle = 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (pcm_device->pcm) { |
|
|
|
if (pcm_device->pcm) { |
|
|
|
pcm_close(pcm_device->pcm); |
|
|
|
pcm_close(pcm_device->pcm); |
|
|
|
pcm_device->pcm = NULL; |
|
|
|
pcm_device->pcm = NULL; |
|
|
@ -3458,7 +3410,6 @@ static int in_close_pcm_devices(struct stream_in *in) |
|
|
|
{ |
|
|
|
{ |
|
|
|
struct pcm_device *pcm_device; |
|
|
|
struct pcm_device *pcm_device; |
|
|
|
struct listnode *node; |
|
|
|
struct listnode *node; |
|
|
|
struct audio_device *adev = in->dev; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
list_for_each(node, &in->pcm_dev_list) { |
|
|
|
list_for_each(node, &in->pcm_dev_list) { |
|
|
|
pcm_device = node_to_item(node, struct pcm_device, stream_list_node); |
|
|
|
pcm_device = node_to_item(node, struct pcm_device, stream_list_node); |
|
|
@ -3466,9 +3417,6 @@ static int in_close_pcm_devices(struct stream_in *in) |
|
|
|
if (pcm_device->pcm) |
|
|
|
if (pcm_device->pcm) |
|
|
|
pcm_close(pcm_device->pcm); |
|
|
|
pcm_close(pcm_device->pcm); |
|
|
|
pcm_device->pcm = NULL; |
|
|
|
pcm_device->pcm = NULL; |
|
|
|
if (pcm_device->sound_trigger_handle > 0) |
|
|
|
|
|
|
|
adev->sound_trigger_close_for_streaming(pcm_device->sound_trigger_handle); |
|
|
|
|
|
|
|
pcm_device->sound_trigger_handle = 0; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
@ -3642,21 +3590,6 @@ static int in_set_gain(struct audio_stream_in *stream, float gain) |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static ssize_t read_bytes_from_dsp(struct stream_in *in, void* buffer, |
|
|
|
|
|
|
|
size_t bytes) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
struct pcm_device *pcm_device; |
|
|
|
|
|
|
|
struct audio_device *adev = in->dev; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pcm_device = node_to_item(list_head(&in->pcm_dev_list), |
|
|
|
|
|
|
|
struct pcm_device, stream_list_node); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (pcm_device->sound_trigger_handle > 0) |
|
|
|
|
|
|
|
return adev->sound_trigger_read_samples(pcm_device->sound_trigger_handle, buffer, bytes); |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static ssize_t in_read(struct audio_stream_in *stream, void *buffer, |
|
|
|
static ssize_t in_read(struct audio_stream_in *stream, void *buffer, |
|
|
|
size_t bytes) |
|
|
|
size_t bytes) |
|
|
|
{ |
|
|
|
{ |
|
|
@ -3708,11 +3641,6 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer, |
|
|
|
false_alarm: |
|
|
|
false_alarm: |
|
|
|
|
|
|
|
|
|
|
|
if (!list_empty(&in->pcm_dev_list)) { |
|
|
|
if (!list_empty(&in->pcm_dev_list)) { |
|
|
|
if (in->usecase == USECASE_AUDIO_CAPTURE_HOTWORD) { |
|
|
|
|
|
|
|
bytes = read_bytes_from_dsp(in, buffer, bytes); |
|
|
|
|
|
|
|
if (bytes > 0) |
|
|
|
|
|
|
|
read_and_process_successful = true; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* Read PCM and: |
|
|
|
* Read PCM and: |
|
|
|
* - resample if needed |
|
|
|
* - resample if needed |
|
|
@ -3723,7 +3651,6 @@ false_alarm: |
|
|
|
if (frames >= 0) |
|
|
|
if (frames >= 0) |
|
|
|
read_and_process_successful = true; |
|
|
|
read_and_process_successful = true; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* Instead of writing zeroes here, we could trust the hardware |
|
|
|
* Instead of writing zeroes here, we could trust the hardware |
|
|
@ -4341,8 +4268,7 @@ static int adev_open_input_stream(struct audio_hw_device *dev, |
|
|
|
audio_channel_count_from_in_mask(config->channel_mask)) != 0) |
|
|
|
audio_channel_count_from_in_mask(config->channel_mask)) != 0) |
|
|
|
return -EINVAL; |
|
|
|
return -EINVAL; |
|
|
|
|
|
|
|
|
|
|
|
usecase_type_t usecase_type = source == AUDIO_SOURCE_HOTWORD ? |
|
|
|
usecase_type_t usecase_type = flags & AUDIO_INPUT_FLAG_FAST ? |
|
|
|
PCM_HOTWORD_STREAMING : flags & AUDIO_INPUT_FLAG_FAST ? |
|
|
|
|
|
|
|
PCM_CAPTURE_LOW_LATENCY : PCM_CAPTURE; |
|
|
|
PCM_CAPTURE_LOW_LATENCY : PCM_CAPTURE; |
|
|
|
pcm_profile = get_pcm_device(usecase_type, devices); |
|
|
|
pcm_profile = get_pcm_device(usecase_type, devices); |
|
|
|
if (pcm_profile == NULL && usecase_type == PCM_CAPTURE_LOW_LATENCY) { |
|
|
|
if (pcm_profile == NULL && usecase_type == PCM_CAPTURE_LOW_LATENCY) { |
|
|
@ -4393,11 +4319,7 @@ static int adev_open_input_stream(struct audio_hw_device *dev, |
|
|
|
in->config = pcm_profile->config; |
|
|
|
in->config = pcm_profile->config; |
|
|
|
|
|
|
|
|
|
|
|
/* Update config params with the requested sample rate and channels */ |
|
|
|
/* Update config params with the requested sample rate and channels */ |
|
|
|
if (source == AUDIO_SOURCE_HOTWORD) { |
|
|
|
|
|
|
|
in->usecase = USECASE_AUDIO_CAPTURE_HOTWORD; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
in->usecase = USECASE_AUDIO_CAPTURE; |
|
|
|
in->usecase = USECASE_AUDIO_CAPTURE; |
|
|
|
} |
|
|
|
|
|
|
|
in->usecase_type = usecase_type; |
|
|
|
in->usecase_type = usecase_type; |
|
|
|
|
|
|
|
|
|
|
|
pthread_mutex_init(&in->lock, (const pthread_mutexattr_t *) NULL); |
|
|
|
pthread_mutex_init(&in->lock, (const pthread_mutexattr_t *) NULL); |
|
|
@ -4587,33 +4509,6 @@ static int adev_open(const hw_module_t *module, const char *name, |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (access(SOUND_TRIGGER_HAL_LIBRARY_PATH, R_OK) == 0) { |
|
|
|
|
|
|
|
adev->sound_trigger_lib = dlopen(SOUND_TRIGGER_HAL_LIBRARY_PATH, RTLD_NOW); |
|
|
|
|
|
|
|
if (adev->sound_trigger_lib == NULL) { |
|
|
|
|
|
|
|
ALOGE("%s: DLOPEN failed for %s", __func__, SOUND_TRIGGER_HAL_LIBRARY_PATH); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
ALOGV("%s: DLOPEN successful for %s", __func__, SOUND_TRIGGER_HAL_LIBRARY_PATH); |
|
|
|
|
|
|
|
adev->sound_trigger_open_for_streaming = |
|
|
|
|
|
|
|
(int (*)(void))dlsym(adev->sound_trigger_lib, |
|
|
|
|
|
|
|
"sound_trigger_open_for_streaming"); |
|
|
|
|
|
|
|
adev->sound_trigger_read_samples = |
|
|
|
|
|
|
|
(size_t (*)(int, void *, size_t))dlsym(adev->sound_trigger_lib, |
|
|
|
|
|
|
|
"sound_trigger_read_samples"); |
|
|
|
|
|
|
|
adev->sound_trigger_close_for_streaming = |
|
|
|
|
|
|
|
(int (*)(int))dlsym(adev->sound_trigger_lib, |
|
|
|
|
|
|
|
"sound_trigger_close_for_streaming"); |
|
|
|
|
|
|
|
if (!adev->sound_trigger_open_for_streaming || |
|
|
|
|
|
|
|
!adev->sound_trigger_read_samples || |
|
|
|
|
|
|
|
!adev->sound_trigger_close_for_streaming) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ALOGE("%s: Error grabbing functions in %s", __func__, SOUND_TRIGGER_HAL_LIBRARY_PATH); |
|
|
|
|
|
|
|
adev->sound_trigger_open_for_streaming = 0; |
|
|
|
|
|
|
|
adev->sound_trigger_read_samples = 0; |
|
|
|
|
|
|
|
adev->sound_trigger_close_for_streaming = 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
adev->voice.session = voice_session_init(adev); |
|
|
|
adev->voice.session = voice_session_init(adev); |
|
|
|
if (adev->voice.session == NULL) { |
|
|
|
if (adev->voice.session == NULL) { |
|
|
|
ALOGE("%s: Failed to initialize voice session data", __func__); |
|
|
|
ALOGE("%s: Failed to initialize voice session data", __func__); |
|
|
|