mirror of
https://github.com/esphome/esphome.git
synced 2025-10-29 14:13:51 +00:00
[audio, microphone] Add MicrophoneSource helper class (#8641)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
@@ -48,6 +48,12 @@ def set_stream_limits(
|
||||
min_sample_rate: int = _UNDEF,
|
||||
max_sample_rate: int = _UNDEF,
|
||||
):
|
||||
"""Sets the limits for the audio stream that audio component can handle
|
||||
|
||||
When the component sinks audio (e.g., a speaker), these indicate the limits to the audio it can receive.
|
||||
When the component sources audio (e.g., a microphone), these indicate the limits to the audio it can send.
|
||||
"""
|
||||
|
||||
def set_limits_in_config(config):
|
||||
if min_bits_per_sample is not _UNDEF:
|
||||
config[CONF_MIN_BITS_PER_SAMPLE] = min_bits_per_sample
|
||||
@@ -69,43 +75,87 @@ def final_validate_audio_schema(
|
||||
name: str,
|
||||
*,
|
||||
audio_device: str,
|
||||
bits_per_sample: int,
|
||||
channels: int,
|
||||
sample_rate: int,
|
||||
bits_per_sample: int = _UNDEF,
|
||||
channels: int = _UNDEF,
|
||||
sample_rate: int = _UNDEF,
|
||||
enabled_channels: list[int] = _UNDEF,
|
||||
audio_device_issue: bool = False,
|
||||
):
|
||||
"""Validates audio compatibility when passed between different components.
|
||||
|
||||
The component derived from ``AUDIO_COMPONENT_SCHEMA`` should call ``set_stream_limits`` in a validator to specify its compatible settings
|
||||
|
||||
- If audio_device_issue is True, then the error message indicates the user should adjust the AUDIO_COMPONENT_SCHEMA derived component's configuration to match the values passed to this function
|
||||
- If audio_device_issue is False, then the error message indicates the user should adjust the configuration of the component calling this function, as it falls out of the valid stream limits
|
||||
|
||||
Args:
|
||||
name (str): Friendly name of the component calling this function with an audio component to validate
|
||||
audio_device (str): The configuration parameter name that contains the ID of an AUDIO_COMPONENT_SCHEMA derived component to validate against
|
||||
bits_per_sample (int, optional): The desired bits per sample
|
||||
channels (int, optional): The desired number of channels
|
||||
sample_rate (int, optional): The desired sample rate
|
||||
enabled_channels (list[int], optional): The desired enabled channels
|
||||
audio_device_issue (bool, optional): Format the error message to indicate the problem is in the configuration for the ``audio_device`` component. Defaults to False.
|
||||
"""
|
||||
|
||||
def validate_audio_compatiblity(audio_config):
|
||||
audio_schema = {}
|
||||
|
||||
try:
|
||||
cv.int_range(
|
||||
min=audio_config.get(CONF_MIN_BITS_PER_SAMPLE),
|
||||
max=audio_config.get(CONF_MAX_BITS_PER_SAMPLE),
|
||||
)(bits_per_sample)
|
||||
except cv.Invalid as exc:
|
||||
raise cv.Invalid(
|
||||
f"Invalid configuration for the {name} component. The {CONF_BITS_PER_SAMPLE} {str(exc)}"
|
||||
) from exc
|
||||
if bits_per_sample is not _UNDEF:
|
||||
try:
|
||||
cv.int_range(
|
||||
min=audio_config.get(CONF_MIN_BITS_PER_SAMPLE),
|
||||
max=audio_config.get(CONF_MAX_BITS_PER_SAMPLE),
|
||||
)(bits_per_sample)
|
||||
except cv.Invalid as exc:
|
||||
if audio_device_issue:
|
||||
error_string = f"Invalid configuration for the specified {audio_device}. The {name} component requires {bits_per_sample} bits per sample."
|
||||
else:
|
||||
error_string = f"Invalid configuration for the {name} component. The {CONF_BITS_PER_SAMPLE} {str(exc)}"
|
||||
raise cv.Invalid(error_string) from exc
|
||||
|
||||
try:
|
||||
cv.int_range(
|
||||
min=audio_config.get(CONF_MIN_CHANNELS),
|
||||
max=audio_config.get(CONF_MAX_CHANNELS),
|
||||
)(channels)
|
||||
except cv.Invalid as exc:
|
||||
raise cv.Invalid(
|
||||
f"Invalid configuration for the {name} component. The {CONF_NUM_CHANNELS} {str(exc)}"
|
||||
) from exc
|
||||
if channels is not _UNDEF:
|
||||
try:
|
||||
cv.int_range(
|
||||
min=audio_config.get(CONF_MIN_CHANNELS),
|
||||
max=audio_config.get(CONF_MAX_CHANNELS),
|
||||
)(channels)
|
||||
except cv.Invalid as exc:
|
||||
if audio_device_issue:
|
||||
error_string = f"Invalid configuration for the specified {audio_device}. The {name} component requires {channels} channels."
|
||||
else:
|
||||
error_string = f"Invalid configuration for the {name} component. The {CONF_NUM_CHANNELS} {str(exc)}"
|
||||
raise cv.Invalid(error_string) from exc
|
||||
|
||||
try:
|
||||
cv.int_range(
|
||||
min=audio_config.get(CONF_MIN_SAMPLE_RATE),
|
||||
max=audio_config.get(CONF_MAX_SAMPLE_RATE),
|
||||
)(sample_rate)
|
||||
return cv.Schema(audio_schema, extra=cv.ALLOW_EXTRA)(audio_config)
|
||||
except cv.Invalid as exc:
|
||||
raise cv.Invalid(
|
||||
f"Invalid configuration for the {name} component. The {CONF_SAMPLE_RATE} {str(exc)}"
|
||||
) from exc
|
||||
if sample_rate is not _UNDEF:
|
||||
try:
|
||||
cv.int_range(
|
||||
min=audio_config.get(CONF_MIN_SAMPLE_RATE),
|
||||
max=audio_config.get(CONF_MAX_SAMPLE_RATE),
|
||||
)(sample_rate)
|
||||
except cv.Invalid as exc:
|
||||
if audio_device_issue:
|
||||
error_string = f"Invalid configuration for the specified {audio_device}. The {name} component requires a {sample_rate} sample rate."
|
||||
else:
|
||||
error_string = f"Invalid configuration for the {name} component. The {CONF_SAMPLE_RATE} {str(exc)}"
|
||||
raise cv.Invalid(error_string) from exc
|
||||
|
||||
if enabled_channels is not _UNDEF:
|
||||
for channel in enabled_channels:
|
||||
try:
|
||||
# Channels are 0-indexed
|
||||
cv.int_range(
|
||||
min=0,
|
||||
max=audio_config.get(CONF_MAX_CHANNELS) - 1,
|
||||
)(channel)
|
||||
except cv.Invalid as exc:
|
||||
if audio_device_issue:
|
||||
error_string = f"Invalid configuration for the specified {audio_device}. The {name} component requires channel {channel}."
|
||||
else:
|
||||
error_string = f"Invalid configuration for the {name} component. Enabled channel {channel} {str(exc)}"
|
||||
raise cv.Invalid(error_string) from exc
|
||||
|
||||
return cv.Schema(audio_schema, extra=cv.ALLOW_EXTRA)(audio_config)
|
||||
|
||||
return cv.Schema(
|
||||
{
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#include "esphome/core/hal.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace esphome {
|
||||
namespace audio {
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "audio_transfer_buffer.h"
|
||||
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/ring_buffer.h"
|
||||
|
||||
#ifdef USE_SPEAKER
|
||||
|
||||
Reference in New Issue
Block a user