add immediate rendering flag
This commit is contained in:
10
README.md
10
README.md
@@ -139,12 +139,11 @@ sudo systemctl status auracast-frontend
|
|||||||
If you want to run the services as a specific user, edit the `User=` line in the service files accordingly.
|
If you want to run the services as a specific user, edit the `User=` line in the service files accordingly.
|
||||||
|
|
||||||
# Setup the audio system
|
# Setup the audio system
|
||||||
|
sudo apt update
|
||||||
|
|
||||||
sudo apt remove -y libportaudio2 portaudio19-dev libportaudiocpp0
|
sudo apt remove -y libportaudio2 portaudio19-dev libportaudiocpp0
|
||||||
echo "y" | rpi-update stable
|
echo "y" | rpi-update stable
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
sudo apt update
|
|
||||||
# TODO: needed ?
|
# TODO: needed ?
|
||||||
sudo apt install pipewire wireplumber pipewire-audio-client-libraries rtkit
|
sudo apt install pipewire wireplumber pipewire-audio-client-libraries rtkit
|
||||||
mkdir -p ~/.config/pipewire/pipewire.conf.d
|
mkdir -p ~/.config/pipewire/pipewire.conf.d
|
||||||
@@ -158,8 +157,7 @@ sudo cpufreq-set -g performance
|
|||||||
|
|
||||||
sudo apt install -y --no-install-recommends \
|
sudo apt install -y --no-install-recommends \
|
||||||
git build-essential cmake pkg-config \
|
git build-essential cmake pkg-config \
|
||||||
libasound2-dev libpulse-dev libjack-jackd2-dev jackd \
|
libasound2-dev libpulse-devpipewire ethtool linuxptp
|
||||||
pipewire ethtool linuxptp
|
|
||||||
|
|
||||||
git clone https://github.com/PortAudio/portaudio.git
|
git clone https://github.com/PortAudio/portaudio.git
|
||||||
cd portaudio
|
cd portaudio
|
||||||
@@ -169,7 +167,7 @@ cmake -S . -B build -G"Unix Makefiles" \
|
|||||||
-DBUILD_SHARED_LIBS=ON \
|
-DBUILD_SHARED_LIBS=ON \
|
||||||
-DPA_USE_ALSA=OFF \
|
-DPA_USE_ALSA=OFF \
|
||||||
-DPA_USE_PULSEAUDIO=ON \
|
-DPA_USE_PULSEAUDIO=ON \
|
||||||
-DPA_USE_JACK=ON
|
-DPA_USE_JACK=OFF
|
||||||
cmake --build build -j$(nproc)
|
cmake --build build -j$(nproc)
|
||||||
sudo cmake --install build # installs to /usr/local/lib
|
sudo cmake --install build # installs to /usr/local/lib
|
||||||
sudo ldconfig # refresh linker cache
|
sudo ldconfig # refresh linker cache
|
||||||
|
|||||||
@@ -35,6 +35,10 @@ class AuracastGlobalConfig(BaseModel):
|
|||||||
presentation_delay_us: int = 40000
|
presentation_delay_us: int = 40000
|
||||||
# TODO:pydantic does not support bytes serialization - use .hex and np.fromhex()
|
# TODO:pydantic does not support bytes serialization - use .hex and np.fromhex()
|
||||||
manufacturer_data: tuple[int, bytes] | tuple[None, None] = (None, None)
|
manufacturer_data: tuple[int, bytes] | tuple[None, None] = (None, None)
|
||||||
|
# LE Audio: Broadcast Audio Immediate Rendering (metadata type 0x09)
|
||||||
|
# When true, include a zero-length LTV with type 0x09 in the subgroup metadata
|
||||||
|
# so receivers may render earlier than the presentation delay for lower latency.
|
||||||
|
immediate_rendering: bool = False
|
||||||
|
|
||||||
# "Audio input. "
|
# "Audio input. "
|
||||||
# "'device' -> use the host's default sound input device, "
|
# "'device' -> use the host's default sound input device, "
|
||||||
|
|||||||
@@ -235,6 +235,30 @@ async def init_broadcast(
|
|||||||
bap_sampling_freq = getattr(bap.SamplingFrequency, f"FREQ_{global_config.auracast_sampling_rate_hz}")
|
bap_sampling_freq = getattr(bap.SamplingFrequency, f"FREQ_{global_config.auracast_sampling_rate_hz}")
|
||||||
bigs = {}
|
bigs = {}
|
||||||
for i, conf in enumerate(big_config):
|
for i, conf in enumerate(big_config):
|
||||||
|
metadata=le_audio.Metadata(
|
||||||
|
[
|
||||||
|
le_audio.Metadata.Entry(
|
||||||
|
tag=le_audio.Metadata.Tag.LANGUAGE, data=conf.language.encode()
|
||||||
|
),
|
||||||
|
le_audio.Metadata.Entry(
|
||||||
|
tag=le_audio.Metadata.Tag.PROGRAM_INFO, data=conf.program_info.encode()
|
||||||
|
),
|
||||||
|
le_audio.Metadata.Entry(
|
||||||
|
tag=le_audio.Metadata.Tag.BROADCAST_NAME, data=conf.name.encode()
|
||||||
|
),
|
||||||
|
]
|
||||||
|
+ (
|
||||||
|
[
|
||||||
|
# Broadcast Audio Immediate Rendering flag (type 0x09), zero-length value
|
||||||
|
le_audio.Metadata.Entry(tag = le_audio.Metadata.Tag.BROADCAST_AUDIO_IMMEDIATE_RENDERING_FLAG, data=b"")
|
||||||
|
]
|
||||||
|
if global_config.immediate_rendering
|
||||||
|
else []
|
||||||
|
)
|
||||||
|
)
|
||||||
|
logging.info(
|
||||||
|
metadata.pretty_print("\n")
|
||||||
|
)
|
||||||
bigs[f'big{i}'] = {}
|
bigs[f'big{i}'] = {}
|
||||||
# Config advertising set
|
# Config advertising set
|
||||||
bigs[f'big{i}']['basic_audio_announcement'] = bap.BasicAudioAnnouncement(
|
bigs[f'big{i}']['basic_audio_announcement'] = bap.BasicAudioAnnouncement(
|
||||||
@@ -247,19 +271,7 @@ async def init_broadcast(
|
|||||||
frame_duration=bap.FrameDuration.DURATION_10000_US,
|
frame_duration=bap.FrameDuration.DURATION_10000_US,
|
||||||
octets_per_codec_frame=global_config.octets_per_frame,
|
octets_per_codec_frame=global_config.octets_per_frame,
|
||||||
),
|
),
|
||||||
metadata=le_audio.Metadata(
|
metadata=metadata,
|
||||||
[
|
|
||||||
le_audio.Metadata.Entry(
|
|
||||||
tag=le_audio.Metadata.Tag.LANGUAGE, data=conf.language.encode()
|
|
||||||
),
|
|
||||||
le_audio.Metadata.Entry(
|
|
||||||
tag=le_audio.Metadata.Tag.PROGRAM_INFO, data=conf.program_info.encode()
|
|
||||||
),
|
|
||||||
le_audio.Metadata.Entry(
|
|
||||||
tag=le_audio.Metadata.Tag.BROADCAST_NAME, data=conf.name.encode()
|
|
||||||
),
|
|
||||||
]
|
|
||||||
),
|
|
||||||
bis=[
|
bis=[
|
||||||
bap.BasicAudioAnnouncement.BIS(
|
bap.BasicAudioAnnouncement.BIS(
|
||||||
index=1,
|
index=1,
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import asyncio
|
|
||||||
import aioconsole
|
|
||||||
from auracast import multicast
|
from auracast import multicast
|
||||||
from auracast import auracast_config
|
from auracast import auracast_config
|
||||||
from auracast.utils.sounddevice_utils import list_usb_pw_inputs, list_network_pw_inputs
|
from auracast.utils.sounddevice_utils import list_usb_pw_inputs, list_network_pw_inputs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
logging.basicConfig( #export LOG_LEVEL=DEBUG
|
logging.basicConfig( #export LOG_LEVEL=DEBUG
|
||||||
@@ -25,8 +22,9 @@ if __name__ == "__main__":
|
|||||||
os.environ.setdefault("AURACAST_SD_BLOCKSIZE", "32")
|
os.environ.setdefault("AURACAST_SD_BLOCKSIZE", "32")
|
||||||
# Accepts 'low'/'high'/'default' or seconds (float). Our shim parses number strings to float.
|
# Accepts 'low'/'high'/'default' or seconds (float). Our shim parses number strings to float.
|
||||||
os.environ.setdefault("AURACAST_SD_LATENCY", "0.0015")
|
os.environ.setdefault("AURACAST_SD_LATENCY", "0.0015")
|
||||||
print("USB pw inputs:")
|
logging.info("USB pw inputs:")
|
||||||
usb_inputs = list_usb_pw_inputs()
|
usb_inputs = list_usb_pw_inputs()
|
||||||
|
logging.info("AEs67 pw inputs:")
|
||||||
aes67_inputs = list_network_pw_inputs()
|
aes67_inputs = list_network_pw_inputs()
|
||||||
for i, d in usb_inputs:
|
for i, d in usb_inputs:
|
||||||
logging.info(f"{i}: {d['name']} in={d['max_input_channels']}")
|
logging.info(f"{i}: {d['name']} in={d['max_input_channels']}")
|
||||||
@@ -62,17 +60,13 @@ if __name__ == "__main__":
|
|||||||
octets_per_frame=OCTETS_PER_FRAME,
|
octets_per_frame=OCTETS_PER_FRAME,
|
||||||
),
|
),
|
||||||
#auracast_config.AuracastBigConfigEng(),
|
#auracast_config.AuracastBigConfigEng(),
|
||||||
|
],
|
||||||
]
|
immediate_rendering=True,
|
||||||
|
qos_config=auracast_config.AuracastQosHigh(),
|
||||||
|
auracast_sampling_rate_hz = LC3_SRATE,
|
||||||
|
octets_per_frame = OCTETS_PER_FRAME, # 32kbps@16kHz
|
||||||
|
transport=TRANSPORT1
|
||||||
)
|
)
|
||||||
|
|
||||||
config.qos_config=auracast_config.AuracastQosHigh()
|
|
||||||
config.transport=TRANSPORT1
|
|
||||||
|
|
||||||
# TODO: encrypted streams are not working
|
|
||||||
|
|
||||||
config.auracast_sampling_rate_hz = LC3_SRATE
|
|
||||||
config.octets_per_frame = OCTETS_PER_FRAME # 32kbps@16kHz
|
|
||||||
#config.debug = True
|
#config.debug = True
|
||||||
|
|
||||||
multicast.run_async(
|
multicast.run_async(
|
||||||
|
|||||||
@@ -14,10 +14,6 @@ print("\nOnly PulseAudio devices:")
|
|||||||
for i, d in devices_by_backend("PulseAudio"):
|
for i, d in devices_by_backend("PulseAudio"):
|
||||||
print(f"{i}: {d['name']} in={d['max_input_channels']} out={d['max_output_channels']}")
|
print(f"{i}: {d['name']} in={d['max_input_channels']} out={d['max_output_channels']}")
|
||||||
|
|
||||||
# Example: only PulseAudio devices on Linux
|
|
||||||
# print("\nOnly JACK devices:")
|
|
||||||
# for i, d in devices_by_backend("JACK"):
|
|
||||||
# print(f"{i}: {d['name']} in={d['max_input_channels']} out={d['max_output_channels']}")
|
|
||||||
|
|
||||||
print("Network pw inputs:")
|
print("Network pw inputs:")
|
||||||
for i, d in list_network_pw_inputs():
|
for i, d in list_network_pw_inputs():
|
||||||
|
|||||||
Reference in New Issue
Block a user