Change default delay for chromecast#2858
Conversation
|
I wonder if we should create a dictionary of Haven't found a list of model names yet.. https://github.com/home-assistant-libs/pychromecast/blob/master/pychromecast/models.py |
|
I think adding a mapping table to model and a default value for the sync delay would make a lot of sense. If one person compares it against a web browser with a wrong offset then the default will already not work. |
|
@kahrendt @maximmaxim345 FYI, any thoughts ? |
Agreed, to seems odd that so many have a negative value. It makes me wonder wether the reference (?VPE) has an atypically large delay |
|
A database seems good, but I'm not fully convinced that even the same two devices types have the same delay. I got one of my Nest Minis pretty close to being in sync now with -484 ms. Using that exact same value on a different Nest Mini had it way off (though I was running a slightly older MA beta, and I think Maxim updated some of that code since then. I'll test it more today on the latest version once everyone in the house wakes up). Sign conventions are always annoying and I tend to get confused! I believe a negative value means we tell the Chromecast to play the audio earlier. In my case, it takes 484 ms from when we tell the Chromecast audio to play to when it is actually played. So, it's not that the VPE has a delay, it's the Chromecast. Maxim should correct me if I have this backwards! |
|
I tested it more and it seems like the same offset works well for all my Nest Minis, so I must have been encountering a bug that has since been fixed when I tested yesterday with an older MA beta. So, I think a database would be a great idea in the long run. I'm hopeful that I can get my offset calculator that uses a microphone a bit more consistent so it's really easy for people to determine this. |
|
Is using manufacturer and model from Device Info (the two only non-optional variables) enough to identify devices for this purpose? Here's some gemini code, I went type safe as nested maps/dicts in python spook me Dataclass versionimport logging
from dataclasses import dataclass, field
from typing import Dict, Optional
@dataclass(frozen=True)
class ModelProfile:
"""Specific configuration for a hardware model."""
name: str
delay_ms: int
@dataclass(frozen=True)
class ManufacturerProfile:
"""Manufacturer settings with a baseline default."""
name: str
default_delay_ms: int
models: Dict[str, ModelProfile] = field(default_factory=dict)
@dataclass(frozen=True)
class HardwareDelayMap:
"""A frozen registry that handles its own resolution logic."""
profiles: Dict[str, ManufacturerProfile]
global_fallback_delay: int = 50
issue_url: str = "https://github.com/your-repo/issues"
def get_delay(self, manufacturer: str, model: str, logger: Optional[logging.Logger] = None) -> int:
"""
Resolves the sync delay. If a default is used, warns the user about
potential sync issues and requests feedback.
"""
# Fallback to a dummy logger if none provided to avoid AttributeErrors
log = logger or logging.getLogger(__name__)
manuf_profile = self.profiles.get(manufacturer)
# 1. Unknown Manufacturer
if not manuf_profile:
log.warning(
"Manufacturer '%s' is not in our database. Using global fallback of %dms. "
"You may experience audio sync issues. If you find the perfect sync value, "
"please create an issue at: %s",
manufacturer, self.global_fallback_delay, self.issue_url
)
return self.global_fallback_delay
# 2. Match specific Model
model_profile = manuf_profile.models.get(model)
if model_profile:
log.debug(
"Exact sync match found: %s %s = %dms",
manuf_profile.name, model_profile.name, model_profile.delay_ms
)
return model_profile.delay_ms
# 3. Fallback to Manufacturer default
log.warning(
"Model '%s' not found for %s. Falling back to manufacturer default: %dms. "
"Audio may be slightly out of sync. Please report the ideal delay at: %s",
model, manuf_profile.name, manuf_profile.default_delay_ms, self.issue_url
)
return manuf_profile.default_delay_ms
# --- Usage ---
# Define the Registry
DELAY_REGISTRY = HardwareDelayMap(
profiles={
"Google Inc.": ManufacturerProfile(
name="Google Inc.",
default_delay_ms=-330,
models={
"Google Nest Mini": ModelProfile(name="Google Nest Mini", delay_ms=-427),
}
)
}
)Heres a less strongly typed versionimport logging
from typing import Dict, Optional
class HardwareDelayMap:
def __init__(self, logger: Optional[logging.Logger] = None) -> None:
self.logger: logging.Logger = logger or logging.getLogger(__name__)
# Structure: { manufacturer_name: { "default": int, model_name: int } }
self._profiles: Dict[str, Dict[str, int]] = {
"Sony": {
"default": 100,
"WH-1000XM4": 150,
"HT-G700": 40,
},
"Bose": {
"default": 80,
"QC45": 160,
},
"Samsung": {
"default": 30,
"HW-Q950A": 0,
}
}
self.global_fallback_delay: int = 50
self.issue_url: str = "https://github.com/your-repo/issues"
def get_delay(self, manufacturer: str, model: str) -> int:
"""
Resolves the sync delay with a clear fallback hierarchy.
"""
manufacturer_map = self._profiles.get(manufacturer)
# 1. Unknown Manufacturer
if manufacturer_map is None:
self.logger.warning(
"Manufacturer '%s' not recognized. Using global fallback: %dms. "
"You may experience sync issues. Report better values at: %s",
manufacturer, self.global_fallback_delay, self.issue_url
)
return self.global_fallback_delay
# 2. Match specific Model (excluding the reserved 'default' key)
if model != "default" and model in manufacturer_map:
delay = manufacturer_map[model]
self.logger.debug("Sync match found: %s %s = %dms", manufacturer, model, delay)
return delay
# 3. Fallback to Manufacturer default
# We use .get() here to safely handle cases where the 'default' key might be missing
manufacturer_default = manufacturer_map.get("default", self.global_fallback_delay)
self.logger.warning(
"Model '%s' not found for manufacturer '%s'. Using default: %dms. "
"You may have sync issues. Report better values at: %s",
model, manufacturer, manufacturer_default, self.issue_url
)
return manufacturer_default |
|
Just waiting for kahrendt's microphone delay tester to launch then will update this PR with some measured values. Leaning towards the less strongly typed implementation as at the moment the dict is static and private. |
|
Ok, I've done some testing using: Sendspin/sendspin-cli#27
N.B KevinA has tested the Google Inc. / Google Nest Mini using his microphone cross-correlation and found -427ms is perfect |
|
@HarvsG any progress here? |
|
superseded by #3689 |
Before #2791, 300 and 350 were used.
On
Google Inc. / Google Home Mini(first gen) approx -330msGoogle Inc. / Google Nest Miniusing his microphone cross-correlation and found -427ms is perfectGoogle Inc. / Chromecast Audioapprox -330 sounds bestGoogle Inc. / Google Nest Hubabout -145 sounds best (confirmed by 1 other user)I think other users should confirm before merge