Skip to content

zdsr: Make the Braille export optional - #181

Merged
ethindp merged 1 commit into
ethindp:masterfrom
qt06:zdsr-optional-braille
Nov 9, 2026
Merged

ethindp merged 1 commit into
ethindp:masterfrom
qt06:zdsr-optional-braille

Conversation

@qt06

@qt06 qt06 commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

Some ZDSR API versions export the four speech functions (InitTTS, Speak, GetSpeakState, StopSpeak) but do not provide Braille. Requiring the Braille export prevented those versions from loading even though speech was available.

Bind Braille independently from the required speech functions. The backend advertises SUPPORTS_BRAILLE only after initialization confirms the export; without it, direct Braille calls return PRISM_ERROR_NOT_IMPLEMENTED, while output continues with speech only. get_features no longer loads the DLL and only reports Braille support after initialization.

Verified with an app-local test DLL exporting the four speech functions but no Braille: initialization succeeds, Braille is not advertised, direct Braille returns not-implemented, and speech-only output succeeds. With the installed API that exports Braille, get_features omits the feature before initialization and reports it after successful initialization. x64 and x86 builds pass, and clang-tidy reports no diagnostics for zdsr.cpp.

Related PRs: #180 fixes optional DLL search precedence; #182 documents the ZDSR-specific Braille behavior together with the independent-channel readiness and process-probe behavior from #177 and #178.

Comment thread doc/src/api/c/backend-functions.md Resolved
Comment thread doc/src/api/c/backend-notes.md Resolved
@qt06
qt06 force-pushed the zdsr-optional-braille branch from e9c349c to 079e005 Compare November 7, 2026 06:36
ethindp pushed a commit that referenced this pull request Nov 8, 2026
`open_optional_library` previously called `LoadLibrary` by bare DLL name
first. Windows could resolve an unrelated same-named copy from the
working directory or `%PATH%`, and Prism would not then try the
product's registered install directory. A stale DLL with a different
export set could therefore make a backend unavailable even though its
registered installation contained a usable DLL.

Search the directory containing Prism first, then the install directory
from the registry when provided, and only then fall back to Windows'
ambient DLL search path. App-local deployments remain supported. The
helper is shared by optional-library backends, so the behavior applies
to all of them; the registry path is only used by backends that provide
one.

Update the backend contribution guidance to document the order and
distinguish required exports from optional exports.

Verified with x64 and x86 Windows builds, clang-tidy, and a
stale-DLL-in-`%PATH%` test: the registered ZDSR installation was
selected instead of the older DLL.

Related ZDSR follow-ups: #181 makes the Braille export optional, and
#182 documents the ZDSR behavior introduced by #177 and #178. This
loader change is independently useful and does not depend on those PRs.

Signed-off-by: qt06 <qt06.com@gmail.com>

@ethindp ethindp left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is much better. Some minor cleanup and then this is ready, I think.

Comment thread source/backends/zdsr.cpp Outdated
class ZdsrBackend final : public TextToSpeechBackend {
private:
std::atomic_flag initialized;
std::atomic<bool> braille_supported{false};

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be an atomic_flag unless you have a good reason to prefer atomic_bool.

Suggested change
std::atomic<bool> braille_supported{false};
std::atomic_flag braille_supported;

Comment thread source/backends/zdsr.cpp Outdated
features |= SUPPORTS_SPEAK | SUPPORTS_OUTPUT | SUPPORTS_IS_SPEAKING |
SUPPORTS_STOP | SUPPORTS_BRAILLE;
SUPPORTS_STOP;
if (braille_supported.load(std::memory_order_acquire))

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (braille_supported.load(std::memory_order_acquire))
if (braille_supported.test(std::memory_order_acquire))

Comment thread source/backends/zdsr.cpp Outdated
return std::unexpected(BackendError::BackendNotAvailable);
if (const auto state = query_speaking(); !state)
return std::unexpected(state.error());
braille_supported.store(api->Braille != nullptr, std::memory_order_release);

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
braille_supported.store(api->Braille != nullptr, std::memory_order_release);
if (api->Braille != nullptr)
braille_supported.test_and_set(std::memory_order_acq_rel);

Comment thread source/backends/zdsr.cpp Outdated
BackendResult<> braille(std::string_view text) override {
if (!initialized.test(std::memory_order_acquire))
return std::unexpected(BackendError::NotInitialized);
if (!braille_supported.load(std::memory_order_acquire))

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (!braille_supported.load(std::memory_order_acquire))
if (!braille_supported.test(std::memory_order_acquire))

Comment thread source/backends/zdsr.cpp Outdated
BackendResult<> output(std::string_view text, bool interrupt) override {
if (const auto res = speak(text, interrupt); !res)
return res;
if (!braille_supported.load(std::memory_order_acquire))

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (!braille_supported.load(std::memory_order_acquire))
if (!braille_supported.test(std::memory_order_acquire))

@qt06
qt06 force-pushed the zdsr-optional-braille branch from 079e005 to d9dbd5a Compare November 8, 2026 03:14
Some ZDSR API versions provide the four speech functions but do not
export Braille. Treating Braille as required prevented those DLLs from
loading even though speech was available.

Bind Braille independently, advertise support only after initialization
confirms the export, return not-implemented for direct Braille calls
when it is absent, and let output continue with speech only. Keep
get_features free of DLL loading side effects.

Signed-off-by: qt06 <qt06.com@gmail.com>
@qt06

qt06 commented Nov 8, 2026

Copy link
Copy Markdown
Contributor Author

Applied all five suggestions in d9dbd5a: braille_supported is now a std::atomic_flag using test()/test_and_set(). Rebuilt x64/x86, and re-ran the no-Braille and with-Braille API tests.

@ethindp
ethindp merged commit efd7e36 into ethindp:master Nov 9, 2026
81 checks passed
ethindp pushed a commit that referenced this pull request Nov 9, 2026
Update the ZDSR backend notes to reflect the merged behavior:

- Runtime support requires both `ZDSRMain.exe` and `ZDSRDaemon.exe`;
service and per-channel processes are not used as the availability
signal.
- With `ZDSRAPI.ini` selecting an independent channel (`type=1`), the
channel may still be starting after `InitTTS` succeeds. Status 9 is
treated as not speaking, so initialization succeeds and `is_speaking`
returns false. `speak` returns `PRISM_ERROR_BACKEND_NOT_AVAILABLE` until
the channel is ready; callers may retry without reinitializing.
- Older ZDSRAPI versions may not export `Braille`. After initialization,
the backend advertises Braille support only when the loaded API provides
that export; otherwise direct Braille calls return
`PRISM_ERROR_NOT_IMPLEMENTED` and `output` uses speech only.

Documentation-only change. The runtime-probe and channel-readiness
behavior was introduced by #177 and #178; the optional Braille behavior
is implemented by #181.

Related PRs: #180 fixes optional DLL search precedence; #181 makes the
ZDSR Braille export optional.

Signed-off-by: qt06 <qt06.com@gmail.com>
@qt06
qt06 deleted the zdsr-optional-braille branch November 9, 2026 06:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants