implement changes for dynamic power setting (#28)
Implements power control for the radios, both radios independent. Reviewed-on: #28 Co-authored-by: pstruebi <struebin.patrick@gmail.com> Co-committed-by: pstruebi <struebin.patrick@gmail.com>
This commit was merged in pull request #28.
This commit is contained in:
@@ -1,5 +1,11 @@
|
|||||||
from typing import List
|
from typing import List
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel, field_validator
|
||||||
|
|
||||||
|
# Discrete TX power levels (dBm) supported by the Nordic SoftDevice Controller
|
||||||
|
# for the nRF radio PA. The HCI controller will clamp requested values to the
|
||||||
|
# nearest supported step. The maximum is bounded by CONFIG_BT_CTLR_TX_PWR_*
|
||||||
|
# in the hci_uart firmware (currently +8 dBm).
|
||||||
|
TX_POWER_VALID = [8, 7, 6, 5, 4, 3, 2, 0, -4, -8, -12, -16, -20]
|
||||||
|
|
||||||
# Define some base to hold the relevant parameters
|
# Define some base to hold the relevant parameters
|
||||||
class AuracastQoSConfig(BaseModel):
|
class AuracastQoSConfig(BaseModel):
|
||||||
@@ -35,6 +41,19 @@ class AuracastGlobalConfig(BaseModel):
|
|||||||
# so receivers may render earlier than the presentation delay for lower latency.
|
# so receivers may render earlier than the presentation delay for lower latency.
|
||||||
immediate_rendering: bool = False
|
immediate_rendering: bool = False
|
||||||
assisted_listening_stream: bool = False
|
assisted_listening_stream: bool = False
|
||||||
|
# Bluetooth advertising TX power for this radio in dBm (per advertising set).
|
||||||
|
# Sent through HCI_LE_Set_Extended_Advertising_Parameters; the SDC clamps to
|
||||||
|
# nearest supported hardware step and propagates to primary/secondary adv,
|
||||||
|
# the periodic advertising train and the BIS ISO PDUs.
|
||||||
|
advertising_tx_power: int = 8
|
||||||
|
|
||||||
|
@field_validator('advertising_tx_power')
|
||||||
|
@classmethod
|
||||||
|
def _snap_tx_power(cls, v: int) -> int:
|
||||||
|
# Snap to the nearest supported discrete step in TX_POWER_VALID.
|
||||||
|
if v in TX_POWER_VALID:
|
||||||
|
return v
|
||||||
|
return min(TX_POWER_VALID, key=lambda s: abs(s - v))
|
||||||
|
|
||||||
# "Audio input. "
|
# "Audio input. "
|
||||||
# "'device' -> use the host's default sound input device, "
|
# "'device' -> use the host's default sound input device, "
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ import bumble.transport
|
|||||||
import bumble.utils
|
import bumble.utils
|
||||||
from bumble.device import Host, AdvertisingChannelMap
|
from bumble.device import Host, AdvertisingChannelMap
|
||||||
from bumble.audio import io as audio_io
|
from bumble.audio import io as audio_io
|
||||||
|
from bumble.vendor.zephyr.hci import HCI_Write_Tx_Power_Level_Command
|
||||||
|
|
||||||
from auracast import auracast_config
|
from auracast import auracast_config
|
||||||
from auracast.utils.read_lc3_file import read_lc3_file
|
from auracast.utils.read_lc3_file import read_lc3_file
|
||||||
@@ -519,7 +520,17 @@ async def init_broadcast(
|
|||||||
advertising_sid=i,
|
advertising_sid=i,
|
||||||
primary_advertising_phy=hci.Phy.LE_1M, # 2m phy config throws error - because for primary advertising channels, 1mbit is only supported
|
primary_advertising_phy=hci.Phy.LE_1M, # 2m phy config throws error - because for primary advertising channels, 1mbit is only supported
|
||||||
secondary_advertising_phy=hci.Phy.LE_1M, # this is the secondary advertising beeing send on non advertising channels (extendend advertising)
|
secondary_advertising_phy=hci.Phy.LE_1M, # this is the secondary advertising beeing send on non advertising channels (extendend advertising)
|
||||||
#advertising_tx_power= # tx power in dbm (max 20)
|
# Pass NO_PREFERENCE (0x7F) here for two reasons:
|
||||||
|
# 1. The Nordic SoftDevice Controller ignores this field for
|
||||||
|
# advertising sets and always returns the compile-time
|
||||||
|
# CONFIG_BT_CTLR_TX_PWR_* value. The real TX power is
|
||||||
|
# applied via the Zephyr VS Write_Tx_Power_Level command
|
||||||
|
# issued right after create_advertising_set() returns.
|
||||||
|
# 2. Bumble's HCI metadata declares this field as 1-byte
|
||||||
|
# *unsigned* (a bumble bug — the BT spec defines it as
|
||||||
|
# signed int8), so negative values would raise
|
||||||
|
# "bytes must be in range(0, 256)" at serialization.
|
||||||
|
advertising_tx_power=hci.HCI_LE_Set_Extended_Advertising_Parameters_Command.TX_POWER_NO_PREFERENCE,
|
||||||
#secondary_advertising_max_skip=10,
|
#secondary_advertising_max_skip=10,
|
||||||
),
|
),
|
||||||
advertising_data=(
|
advertising_data=(
|
||||||
@@ -536,6 +547,48 @@ async def init_broadcast(
|
|||||||
auto_start=True,
|
auto_start=True,
|
||||||
)
|
)
|
||||||
bigs[f'big{i}']['advertising_set'] = advertising_set
|
bigs[f'big{i}']['advertising_set'] = advertising_set
|
||||||
|
# NOTE: selected_tx_power below reflects the SDC's compile-time max
|
||||||
|
# (LE_Set_Ext_Adv_Params was sent with NO_PREFERENCE). The actual
|
||||||
|
# transmit power is set by the VS Write_Tx_Power_Level call below.
|
||||||
|
logging.debug(
|
||||||
|
'LE_Set_Ext_Adv_Params reports controller fallback TX power: %+d dBm (handle=%d)',
|
||||||
|
getattr(advertising_set, 'selected_tx_power', 0),
|
||||||
|
i,
|
||||||
|
)
|
||||||
|
|
||||||
|
# The Nordic SoftDevice Controller does not honor the per-set
|
||||||
|
# advertising_tx_power passed in HCI_LE_Set_Extended_Advertising_Parameters
|
||||||
|
# (it returns the compile-time CONFIG_BT_CTLR_TX_PWR_* value regardless).
|
||||||
|
# Apply the requested level via the Zephyr Vendor-Specific HCI command
|
||||||
|
# Write_Tx_Power_Level (opcode 0xFC0E), which the SDC honors per
|
||||||
|
# advertising handle. The SDC clamps the value to the nearest supported
|
||||||
|
# hardware step (max bounded by CONFIG_BT_CTLR_TX_PWR_PLUS_8).
|
||||||
|
try:
|
||||||
|
adv_handle = getattr(advertising_set, 'advertising_handle', i)
|
||||||
|
response = await device.send_command(
|
||||||
|
HCI_Write_Tx_Power_Level_Command(
|
||||||
|
handle_type=HCI_Write_Tx_Power_Level_Command.TX_POWER_HANDLE_TYPE_ADV,
|
||||||
|
connection_handle=adv_handle,
|
||||||
|
tx_power_level=global_config.advertising_tx_power,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
rp = getattr(response, 'return_parameters', None)
|
||||||
|
status = getattr(rp, 'status', 0xFF) if rp is not None else 0xFF
|
||||||
|
selected = getattr(rp, 'selected_tx_power_level', None) if rp is not None else None
|
||||||
|
if status == 0 and selected is not None:
|
||||||
|
logging.info(
|
||||||
|
'Advertising TX power (VS Write_Tx_Power_Level): requested=%+d dBm, controller selected=%+d dBm (handle=%d)',
|
||||||
|
global_config.advertising_tx_power,
|
||||||
|
selected,
|
||||||
|
adv_handle,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
logging.warning(
|
||||||
|
'VS Write_Tx_Power_Level failed: status=0x%02X handle=%d requested=%+d dBm',
|
||||||
|
status, adv_handle, global_config.advertising_tx_power,
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logging.warning('VS Write_Tx_Power_Level not supported by controller: %s', e)
|
||||||
|
|
||||||
logging.info('Start Periodic Advertising')
|
logging.info('Start Periodic Advertising')
|
||||||
await advertising_set.start_periodic()
|
await advertising_set.start_periodic()
|
||||||
|
|||||||
@@ -96,6 +96,36 @@ QOS_PRESET_MAP = {
|
|||||||
"Robust": auracast_config.AuracastQosRobust(),
|
"Robust": auracast_config.AuracastQosRobust(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Discrete advertising TX power steps in dBm supported by the Nordic SDC radio
|
||||||
|
# PA. Sent through HCI_LE_Set_Extended_Advertising_Parameters; the controller
|
||||||
|
# clamps to the nearest hardware step.
|
||||||
|
TX_POWER_OPTIONS = [8, 7, 6, 5, 4, 3, 2, 0, -4, -8, -12, -16, -20]
|
||||||
|
TX_POWER_DEFAULT = 8
|
||||||
|
|
||||||
|
|
||||||
|
def _coerce_tx_power(value, default: int = TX_POWER_DEFAULT) -> int:
|
||||||
|
try:
|
||||||
|
v = int(value)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
return default
|
||||||
|
if v in TX_POWER_OPTIONS:
|
||||||
|
return v
|
||||||
|
return min(TX_POWER_OPTIONS, key=lambda s: abs(s - v))
|
||||||
|
|
||||||
|
|
||||||
|
def _tx_power_selectbox(label: str, key: str, default: int, disabled: bool, help_text: str | None = None) -> int:
|
||||||
|
snapped = _coerce_tx_power(default)
|
||||||
|
idx = TX_POWER_OPTIONS.index(snapped)
|
||||||
|
return st.selectbox(
|
||||||
|
label,
|
||||||
|
TX_POWER_OPTIONS,
|
||||||
|
index=idx,
|
||||||
|
key=key,
|
||||||
|
format_func=lambda v: f"{v:+d} dBm",
|
||||||
|
disabled=disabled,
|
||||||
|
help=help_text or "Bluetooth advertising TX power for this radio. Higher values increase range; lower values reduce interference and power draw.",
|
||||||
|
)
|
||||||
|
|
||||||
# Try loading persisted settings from backend
|
# Try loading persisted settings from backend
|
||||||
saved_settings = {}
|
saved_settings = {}
|
||||||
try:
|
try:
|
||||||
@@ -394,6 +424,22 @@ if audio_mode == "Demo":
|
|||||||
disabled=is_streaming,
|
disabled=is_streaming,
|
||||||
help="Fast: 2 retransmissions, lower latency. Robust: 4 retransmissions, better reliability."
|
help="Fast: 2 retransmissions, lower latency. Robust: 4 retransmissions, better reliability."
|
||||||
)
|
)
|
||||||
|
# Per-radio TX power for Demo (independent for R1 and R2)
|
||||||
|
col_tx_r1, col_tx_r2 = st.columns(2, gap="small")
|
||||||
|
with col_tx_r1:
|
||||||
|
tx_power_r1 = _tx_power_selectbox(
|
||||||
|
"TX Power (R1)",
|
||||||
|
key="demo_tx_power_r1",
|
||||||
|
default=saved_settings.get('advertising_tx_power', TX_POWER_DEFAULT),
|
||||||
|
disabled=is_streaming,
|
||||||
|
)
|
||||||
|
with col_tx_r2:
|
||||||
|
tx_power_r2 = _tx_power_selectbox(
|
||||||
|
"TX Power (R2)",
|
||||||
|
key="demo_tx_power_r2",
|
||||||
|
default=saved_settings.get('secondary', {}).get('advertising_tx_power', TX_POWER_DEFAULT),
|
||||||
|
disabled=is_streaming,
|
||||||
|
)
|
||||||
#st.info(f"Demo mode selected: {demo_selected} (Streams: {demo_stream_map[demo_selected]['streams']}, Rate: {demo_stream_map[demo_selected]['rate']} Hz)")
|
#st.info(f"Demo mode selected: {demo_selected} (Streams: {demo_stream_map[demo_selected]['streams']}, Rate: {demo_stream_map[demo_selected]['rate']} Hz)")
|
||||||
quality = None # Not used in demo mode
|
quality = None # Not used in demo mode
|
||||||
else:
|
else:
|
||||||
@@ -490,6 +536,13 @@ else:
|
|||||||
help="Fast: 2 retransmissions, lower latency. Robust: 4 retransmissions, better reliability."
|
help="Fast: 2 retransmissions, lower latency. Robust: 4 retransmissions, better reliability."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
tx_power_r1 = _tx_power_selectbox(
|
||||||
|
"TX Power (R1)",
|
||||||
|
key="analog_tx_power_r1",
|
||||||
|
default=saved_settings.get('advertising_tx_power', TX_POWER_DEFAULT),
|
||||||
|
disabled=is_streaming,
|
||||||
|
)
|
||||||
|
|
||||||
col_r1_name, col_r1_lang = st.columns([2, 1])
|
col_r1_name, col_r1_lang = st.columns([2, 1])
|
||||||
with col_r1_name:
|
with col_r1_name:
|
||||||
stream_name1 = st.text_input(
|
stream_name1 = st.text_input(
|
||||||
@@ -658,6 +711,13 @@ else:
|
|||||||
help="Fast: 2 retransmissions, lower latency. Robust: 4 retransmissions, better reliability."
|
help="Fast: 2 retransmissions, lower latency. Robust: 4 retransmissions, better reliability."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
tx_power_r2 = _tx_power_selectbox(
|
||||||
|
"TX Power (R2)",
|
||||||
|
key="analog_tx_power_r2",
|
||||||
|
default=saved_settings.get('secondary', {}).get('advertising_tx_power', TX_POWER_DEFAULT),
|
||||||
|
disabled=is_streaming,
|
||||||
|
)
|
||||||
|
|
||||||
col_r2_name, col_r2_lang = st.columns([2, 1])
|
col_r2_name, col_r2_lang = st.columns([2, 1])
|
||||||
with col_r2_name:
|
with col_r2_name:
|
||||||
stream_name2 = st.text_input(
|
stream_name2 = st.text_input(
|
||||||
@@ -713,6 +773,7 @@ else:
|
|||||||
'immediate_rendering': immediate_rendering2,
|
'immediate_rendering': immediate_rendering2,
|
||||||
'presentation_delay_ms': presentation_delay_ms2,
|
'presentation_delay_ms': presentation_delay_ms2,
|
||||||
'qos_preset': qos_preset2,
|
'qos_preset': qos_preset2,
|
||||||
|
'tx_power': tx_power_r2,
|
||||||
'analog_gain_db_left': analog_gain_db_left,
|
'analog_gain_db_left': analog_gain_db_left,
|
||||||
'analog_gain_db_right': analog_gain_db_right,
|
'analog_gain_db_right': analog_gain_db_right,
|
||||||
}
|
}
|
||||||
@@ -729,6 +790,7 @@ else:
|
|||||||
'immediate_rendering': immediate_rendering1,
|
'immediate_rendering': immediate_rendering1,
|
||||||
'presentation_delay_ms': presentation_delay_ms1,
|
'presentation_delay_ms': presentation_delay_ms1,
|
||||||
'qos_preset': qos_preset1,
|
'qos_preset': qos_preset1,
|
||||||
|
'tx_power': tx_power_r1,
|
||||||
'stereo_mode': stereo_enabled,
|
'stereo_mode': stereo_enabled,
|
||||||
'analog_gain_db_left': analog_gain_db_left,
|
'analog_gain_db_left': analog_gain_db_left,
|
||||||
'analog_gain_db_right': analog_gain_db_right,
|
'analog_gain_db_right': analog_gain_db_right,
|
||||||
@@ -907,7 +969,14 @@ else:
|
|||||||
disabled=is_streaming,
|
disabled=is_streaming,
|
||||||
help="Quality of Service preset for Radio 1"
|
help="Quality of Service preset for Radio 1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
r1_tx_power = _tx_power_selectbox(
|
||||||
|
"TX Power (R1)",
|
||||||
|
key="dante_tx_power_r1",
|
||||||
|
default=saved_r1_config.get('advertising_tx_power', saved_settings.get('advertising_tx_power', TX_POWER_DEFAULT)),
|
||||||
|
disabled=is_streaming,
|
||||||
|
)
|
||||||
|
|
||||||
# Per-stream configuration for Radio 1
|
# Per-stream configuration for Radio 1
|
||||||
if dante_stereo_enabled:
|
if dante_stereo_enabled:
|
||||||
st.write("**Stereo Stream Configuration (Radio 1)**")
|
st.write("**Stereo Stream Configuration (Radio 1)**")
|
||||||
@@ -1188,7 +1257,14 @@ else:
|
|||||||
disabled=is_streaming,
|
disabled=is_streaming,
|
||||||
help="Quality of Service preset for Radio 2"
|
help="Quality of Service preset for Radio 2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
r2_tx_power = _tx_power_selectbox(
|
||||||
|
"TX Power (R2)",
|
||||||
|
key="dante_tx_power_r2",
|
||||||
|
default=saved_r2_config.get('advertising_tx_power', saved_settings.get('secondary', {}).get('advertising_tx_power', TX_POWER_DEFAULT)),
|
||||||
|
disabled=is_streaming,
|
||||||
|
)
|
||||||
|
|
||||||
# Per-stream configuration for Radio 2
|
# Per-stream configuration for Radio 2
|
||||||
st.write("**Stream Configuration (Radio 2)**")
|
st.write("**Stream Configuration (Radio 2)**")
|
||||||
r2_streams = []
|
r2_streams = []
|
||||||
@@ -1304,6 +1380,7 @@ else:
|
|||||||
r2_immediate_rendering = False
|
r2_immediate_rendering = False
|
||||||
r2_presentation_delay_ms = 40
|
r2_presentation_delay_ms = 40
|
||||||
r2_qos_preset = 'Fast'
|
r2_qos_preset = 'Fast'
|
||||||
|
r2_tx_power = TX_POWER_DEFAULT
|
||||||
|
|
||||||
# Validate unique input devices for Network - Dante mode
|
# Validate unique input devices for Network - Dante mode
|
||||||
if audio_mode == "Network - Dante":
|
if audio_mode == "Network - Dante":
|
||||||
@@ -1335,6 +1412,7 @@ else:
|
|||||||
'immediate_rendering': r1_immediate_rendering,
|
'immediate_rendering': r1_immediate_rendering,
|
||||||
'presentation_delay_ms': r1_presentation_delay_ms,
|
'presentation_delay_ms': r1_presentation_delay_ms,
|
||||||
'qos_preset': r1_qos_preset,
|
'qos_preset': r1_qos_preset,
|
||||||
|
'tx_power': r1_tx_power,
|
||||||
'dante_stereo_mode': dante_stereo_enabled,
|
'dante_stereo_mode': dante_stereo_enabled,
|
||||||
'dante_stereo_left': dante_left_channel,
|
'dante_stereo_left': dante_left_channel,
|
||||||
'dante_stereo_right': dante_right_channel,
|
'dante_stereo_right': dante_right_channel,
|
||||||
@@ -1350,6 +1428,7 @@ else:
|
|||||||
'immediate_rendering': r2_immediate_rendering if radio2_enabled else False,
|
'immediate_rendering': r2_immediate_rendering if radio2_enabled else False,
|
||||||
'presentation_delay_ms': r2_presentation_delay_ms if radio2_enabled else 40000,
|
'presentation_delay_ms': r2_presentation_delay_ms if radio2_enabled else 40000,
|
||||||
'qos_preset': r2_qos_preset if radio2_enabled else 'Fast',
|
'qos_preset': r2_qos_preset if radio2_enabled else 'Fast',
|
||||||
|
'tx_power': r2_tx_power if radio2_enabled else TX_POWER_DEFAULT,
|
||||||
} if radio2_enabled else None
|
} if radio2_enabled else None
|
||||||
|
|
||||||
if audio_mode in ("USB", "Network"):
|
if audio_mode in ("USB", "Network"):
|
||||||
@@ -1406,6 +1485,13 @@ else:
|
|||||||
help="Fast: 2 retransmissions, lower latency. Robust: 4 retransmissions, better reliability."
|
help="Fast: 2 retransmissions, lower latency. Robust: 4 retransmissions, better reliability."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
tx_power = _tx_power_selectbox(
|
||||||
|
"TX Power",
|
||||||
|
key="usb_tx_power",
|
||||||
|
default=saved_settings.get('advertising_tx_power', TX_POWER_DEFAULT),
|
||||||
|
disabled=is_streaming,
|
||||||
|
)
|
||||||
|
|
||||||
stream_name = st.text_input(
|
stream_name = st.text_input(
|
||||||
"Channel Name",
|
"Channel Name",
|
||||||
value=default_name,
|
value=default_name,
|
||||||
@@ -1559,6 +1645,7 @@ if start_stream:
|
|||||||
immediate_rendering=immediate_rendering,
|
immediate_rendering=immediate_rendering,
|
||||||
presentation_delay_us=int(presentation_delay_ms * 1000),
|
presentation_delay_us=int(presentation_delay_ms * 1000),
|
||||||
qos_config=QOS_PRESET_MAP[qos_preset],
|
qos_config=QOS_PRESET_MAP[qos_preset],
|
||||||
|
advertising_tx_power=tx_power_r1,
|
||||||
bigs=bigs1
|
bigs=bigs1
|
||||||
)
|
)
|
||||||
config2 = None
|
config2 = None
|
||||||
@@ -1571,6 +1658,7 @@ if start_stream:
|
|||||||
immediate_rendering=immediate_rendering,
|
immediate_rendering=immediate_rendering,
|
||||||
presentation_delay_us=int(presentation_delay_ms * 1000),
|
presentation_delay_us=int(presentation_delay_ms * 1000),
|
||||||
qos_config=QOS_PRESET_MAP[qos_preset],
|
qos_config=QOS_PRESET_MAP[qos_preset],
|
||||||
|
advertising_tx_power=tx_power_r2,
|
||||||
bigs=bigs2
|
bigs=bigs2
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1614,6 +1702,7 @@ if start_stream:
|
|||||||
immediate_rendering=bool(cfg['immediate_rendering']),
|
immediate_rendering=bool(cfg['immediate_rendering']),
|
||||||
presentation_delay_us=int(cfg['presentation_delay_ms'] * 1000),
|
presentation_delay_us=int(cfg['presentation_delay_ms'] * 1000),
|
||||||
qos_config=QOS_PRESET_MAP[cfg['qos_preset']],
|
qos_config=QOS_PRESET_MAP[cfg['qos_preset']],
|
||||||
|
advertising_tx_power=int(cfg.get('tx_power', TX_POWER_DEFAULT)),
|
||||||
analog_gain_db_left=cfg.get('analog_gain_db_left', 0.0),
|
analog_gain_db_left=cfg.get('analog_gain_db_left', 0.0),
|
||||||
analog_gain_db_right=cfg.get('analog_gain_db_right', 0.0),
|
analog_gain_db_right=cfg.get('analog_gain_db_right', 0.0),
|
||||||
bigs=[
|
bigs=[
|
||||||
@@ -1701,6 +1790,7 @@ if start_stream:
|
|||||||
immediate_rendering=bool(radio_cfg['immediate_rendering']),
|
immediate_rendering=bool(radio_cfg['immediate_rendering']),
|
||||||
presentation_delay_us=int(radio_cfg['presentation_delay_ms'] * 1000),
|
presentation_delay_us=int(radio_cfg['presentation_delay_ms'] * 1000),
|
||||||
qos_config=QOS_PRESET_MAP[radio_cfg['qos_preset']],
|
qos_config=QOS_PRESET_MAP[radio_cfg['qos_preset']],
|
||||||
|
advertising_tx_power=int(radio_cfg.get('tx_power', TX_POWER_DEFAULT)),
|
||||||
bigs=bigs
|
bigs=bigs
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1736,6 +1826,7 @@ if start_stream:
|
|||||||
immediate_rendering=immediate_rendering,
|
immediate_rendering=immediate_rendering,
|
||||||
presentation_delay_us=int(presentation_delay_ms * 1000),
|
presentation_delay_us=int(presentation_delay_ms * 1000),
|
||||||
qos_config=QOS_PRESET_MAP[qos_preset],
|
qos_config=QOS_PRESET_MAP[qos_preset],
|
||||||
|
advertising_tx_power=tx_power,
|
||||||
bigs=[
|
bigs=[
|
||||||
auracast_config.AuracastBigConfig(
|
auracast_config.AuracastBigConfig(
|
||||||
code=(stream_passwort.strip() or None),
|
code=(stream_passwort.strip() or None),
|
||||||
|
|||||||
@@ -585,6 +585,7 @@ async def init_radio(transport: str, conf: auracast_config.AuracastConfigGroup,
|
|||||||
'analog_stereo_mode': getattr(conf.bigs[0], 'analog_stereo_mode', False) if conf.bigs else False,
|
'analog_stereo_mode': getattr(conf.bigs[0], 'analog_stereo_mode', False) if conf.bigs else False,
|
||||||
'analog_gain_db_left': getattr(conf, 'analog_gain_db_left', 0.0),
|
'analog_gain_db_left': getattr(conf, 'analog_gain_db_left', 0.0),
|
||||||
'analog_gain_db_right': getattr(conf, 'analog_gain_db_right', 0.0),
|
'analog_gain_db_right': getattr(conf, 'analog_gain_db_right', 0.0),
|
||||||
|
'advertising_tx_power': getattr(conf, 'advertising_tx_power', 8),
|
||||||
'stream_password': (conf.bigs[0].code if conf.bigs and getattr(conf.bigs[0], 'code', None) else None),
|
'stream_password': (conf.bigs[0].code if conf.bigs and getattr(conf.bigs[0], 'code', None) else None),
|
||||||
'big_ids': [getattr(big, 'id', DEFAULT_BIG_ID) for big in conf.bigs],
|
'big_ids': [getattr(big, 'id', DEFAULT_BIG_ID) for big in conf.bigs],
|
||||||
'big_random_addresses': [getattr(big, 'random_address', DEFAULT_RANDOM_ADDRESS) for big in conf.bigs],
|
'big_random_addresses': [getattr(big, 'random_address', DEFAULT_RANDOM_ADDRESS) for big in conf.bigs],
|
||||||
@@ -755,11 +756,12 @@ async def _autostart_from_settings():
|
|||||||
big_ids = settings.get('big_ids') or []
|
big_ids = settings.get('big_ids') or []
|
||||||
big_addrs = settings.get('big_random_addresses') or []
|
big_addrs = settings.get('big_random_addresses') or []
|
||||||
stream_password = settings.get('stream_password')
|
stream_password = settings.get('stream_password')
|
||||||
|
tx_power = int(settings.get('advertising_tx_power', 8))
|
||||||
original_ts = settings.get('timestamp')
|
original_ts = settings.get('timestamp')
|
||||||
previously_streaming = bool(settings.get('is_streaming'))
|
previously_streaming = bool(settings.get('is_streaming'))
|
||||||
|
|
||||||
log.info(
|
log.info(
|
||||||
"[AUTOSTART][PRIMARY] loaded settings: previously_streaming=%s audio_mode=%s rate=%s octets=%s pres_delay=%s qos_preset=%s immediate_rendering=%s assisted_listening_stream=%s demo_sources=%s",
|
"[AUTOSTART][PRIMARY] loaded settings: previously_streaming=%s audio_mode=%s rate=%s octets=%s pres_delay=%s qos_preset=%s immediate_rendering=%s assisted_listening_stream=%s tx_power=%+d dBm demo_sources=%s",
|
||||||
previously_streaming,
|
previously_streaming,
|
||||||
audio_mode,
|
audio_mode,
|
||||||
rate,
|
rate,
|
||||||
@@ -768,6 +770,7 @@ async def _autostart_from_settings():
|
|||||||
saved_qos_preset,
|
saved_qos_preset,
|
||||||
immediate_rendering,
|
immediate_rendering,
|
||||||
assisted_listening_stream,
|
assisted_listening_stream,
|
||||||
|
tx_power,
|
||||||
(settings.get('demo_sources') or []),
|
(settings.get('demo_sources') or []),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -817,6 +820,7 @@ async def _autostart_from_settings():
|
|||||||
immediate_rendering=immediate_rendering,
|
immediate_rendering=immediate_rendering,
|
||||||
assisted_listening_stream=assisted_listening_stream,
|
assisted_listening_stream=assisted_listening_stream,
|
||||||
presentation_delay_us=pres_delay if pres_delay is not None else 40000,
|
presentation_delay_us=pres_delay if pres_delay is not None else 40000,
|
||||||
|
advertising_tx_power=tx_power,
|
||||||
bigs=bigs,
|
bigs=bigs,
|
||||||
)
|
)
|
||||||
# Set num_bis for stereo mode if needed
|
# Set num_bis for stereo mode if needed
|
||||||
@@ -886,6 +890,7 @@ async def _autostart_from_settings():
|
|||||||
presentation_delay_us=pres_delay if pres_delay is not None else 40000,
|
presentation_delay_us=pres_delay if pres_delay is not None else 40000,
|
||||||
analog_gain_db_left=settings.get('analog_gain_db_left', 0.0),
|
analog_gain_db_left=settings.get('analog_gain_db_left', 0.0),
|
||||||
analog_gain_db_right=settings.get('analog_gain_db_right', 0.0),
|
analog_gain_db_right=settings.get('analog_gain_db_right', 0.0),
|
||||||
|
advertising_tx_power=tx_power,
|
||||||
bigs=bigs,
|
bigs=bigs,
|
||||||
)
|
)
|
||||||
# Set num_bis for stereo mode if needed
|
# Set num_bis for stereo mode if needed
|
||||||
@@ -921,10 +926,11 @@ async def _autostart_from_settings():
|
|||||||
big_ids = settings.get('big_ids') or []
|
big_ids = settings.get('big_ids') or []
|
||||||
big_addrs = settings.get('big_random_addresses') or []
|
big_addrs = settings.get('big_random_addresses') or []
|
||||||
stream_password = settings.get('stream_password')
|
stream_password = settings.get('stream_password')
|
||||||
|
tx_power = int(settings.get('advertising_tx_power', 8))
|
||||||
original_ts = settings.get('timestamp')
|
original_ts = settings.get('timestamp')
|
||||||
previously_streaming = bool(settings.get('is_streaming'))
|
previously_streaming = bool(settings.get('is_streaming'))
|
||||||
log.info(
|
log.info(
|
||||||
"[AUTOSTART][SECONDARY] loaded settings: previously_streaming=%s audio_mode=%s rate=%s octets=%s pres_delay=%s qos_preset=%s immediate_rendering=%s assisted_listening_stream=%s demo_sources=%s",
|
"[AUTOSTART][SECONDARY] loaded settings: previously_streaming=%s audio_mode=%s rate=%s octets=%s pres_delay=%s qos_preset=%s immediate_rendering=%s assisted_listening_stream=%s tx_power=%+d dBm demo_sources=%s",
|
||||||
previously_streaming,
|
previously_streaming,
|
||||||
audio_mode,
|
audio_mode,
|
||||||
rate,
|
rate,
|
||||||
@@ -933,6 +939,7 @@ async def _autostart_from_settings():
|
|||||||
saved_qos_preset,
|
saved_qos_preset,
|
||||||
immediate_rendering,
|
immediate_rendering,
|
||||||
assisted_listening_stream,
|
assisted_listening_stream,
|
||||||
|
tx_power,
|
||||||
(settings.get('demo_sources') or []),
|
(settings.get('demo_sources') or []),
|
||||||
)
|
)
|
||||||
if not previously_streaming:
|
if not previously_streaming:
|
||||||
@@ -972,6 +979,7 @@ async def _autostart_from_settings():
|
|||||||
immediate_rendering=immediate_rendering,
|
immediate_rendering=immediate_rendering,
|
||||||
assisted_listening_stream=assisted_listening_stream,
|
assisted_listening_stream=assisted_listening_stream,
|
||||||
presentation_delay_us=pres_delay if pres_delay is not None else 40000,
|
presentation_delay_us=pres_delay if pres_delay is not None else 40000,
|
||||||
|
advertising_tx_power=tx_power,
|
||||||
bigs=bigs,
|
bigs=bigs,
|
||||||
)
|
)
|
||||||
conf.qos_config = QOS_PRESET_MAP.get(saved_qos_preset, QOS_PRESET_MAP["Fast"])
|
conf.qos_config = QOS_PRESET_MAP.get(saved_qos_preset, QOS_PRESET_MAP["Fast"])
|
||||||
@@ -1041,6 +1049,7 @@ async def _autostart_from_settings():
|
|||||||
presentation_delay_us=pres_delay if pres_delay is not None else 40000,
|
presentation_delay_us=pres_delay if pres_delay is not None else 40000,
|
||||||
analog_gain_db_left=settings.get('analog_gain_db_left', 0.0),
|
analog_gain_db_left=settings.get('analog_gain_db_left', 0.0),
|
||||||
analog_gain_db_right=settings.get('analog_gain_db_right', 0.0),
|
analog_gain_db_right=settings.get('analog_gain_db_right', 0.0),
|
||||||
|
advertising_tx_power=tx_power,
|
||||||
bigs=bigs,
|
bigs=bigs,
|
||||||
)
|
)
|
||||||
conf.qos_config = QOS_PRESET_MAP.get(saved_qos_preset, QOS_PRESET_MAP["Fast"])
|
conf.qos_config = QOS_PRESET_MAP.get(saved_qos_preset, QOS_PRESET_MAP["Fast"])
|
||||||
|
|||||||
22623
src/openocd/merged.hex
22623
src/openocd/merged.hex
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user