brailcom/speechd

speechd Module as shared library

Closed this issue · 12 comments

Is your feature request related to a problem? Please describe.
When working on a speechd module, i was a bit frustrated in terms of architecture itself how speechd modules are beeing generally made.

Describe the solution you'd like
I propose, instead of spawning a process of a module, make it as a shared library, which would be loaded on request. I know, pipes are fast enough in linux, but as this project is a speech server, it should achieve as mutch performance as it can. Defining good enough C-api for a shared library will also make easier to write a module, and not implement ssip protocol ourselves, as now we should stick with sd source tree or reinvent a wheel and waste a time implementing things we don't need to implement at all. Also having a good api will allow us to write module in any language without a pain.

Describe alternatives you've considered
N/A

Additional context
N/a

not implement ssip protocol ourselves

? There is really no need to implement ssip by hand.

Did you read https://htmlpreview.github.io/?https://github.com/brailcom/speechd/blob/master/doc/speech-dispatcher.html#How-to-Write-New-Output-Module ? It describes how to write a new module by filling a skeleton, which is essentially like writing a loadable shared library plugin.

As i already stated, this will lead to use sd source tree and C, in any other case, we will need to implement ssip by hand.

As i already stated, this will lead to use sd source tree and C,

You can provide the required functions in whatever language that can provide a function with a given C signature.

That's exactly like your proposal for a library-based loadable module, it'd have to provide functions with given C signatures.

I think we have some missunderstanding here.

You are saying that we can use skeleton to make a module.
I am saying, that this will lead us to depend or grab C source code from speechd.
If i want to write a module in rust, what will be my steps?
I will need to re-implement all the same ssip protocol to conform with speech api.
Am i correct or not?

You are saying that we can use skeleton to make a module.

No, I'm saying that you can look at the skeleton to determine what the function is supposed to be doing.

If i want to write a module in rust, what will be my steps?

Provide the rust functions that provide the expected C interface, and achieve in them what the skeleton advises to do.

We could provide a rust-based skeleton file, that'd be a very welcome contribution

Skeleton is using module_main.h.
I, personally, don't want to poke arround spd source to create my own module.
How i can write a module in rust without including these portions of code if all logic of ipc is implemented there?

Instead of using one language, i will need use two just to use ssip implementation, and if something will be changed in spd, i will need to synchronize that portion of code.

Skeleton is using module_main.h.

To get access to module helpers, yes. You'd have exactly the same with a plugin-based approach, since the plugin would need to push audio frames, report events, etc.

But that's not a problem: rust can call C functions just fine.

I, personally, don't want to poke arround spd source to create my own module.

With a plugin approach you would really have the same. Really, the interface you'd have with a plugin approach would be essentially the same as module_main.h.

How i can write a module in rust without including these portions of code if all logic of ipc is implemented there?

You don't need to include the .h file, you can just declare the functions the way rust does to be able to call C functions. Again, that'd be the same with a plugin approach.

All you need is it to eventually link your rust object with the module_* files, just like is done for the skeleton example. We could even make that a library so it's even easier.

if something will be changed in spd, i will need to synchronize that portion of code

The module interface is not meant to change. Exactly just like a plugin interface would not be either.

Really, there is no programmatic difference between a plugin approach and the current process-with-helpers approach.

The interface would be defined as a C header, both in terms of what functions the module is expected to provide, and what functions it can call. And that's what languages have been doing for interacting with other languages' world.

There are however huge differences in terms of reliability, flexibility, licensing etc. between process-based and plugin: if a speech engine crashes, that just crashes that module. If the speech engine messes up with the process state, that affects only that engine, we can even keep the synth in a separate snap with separate process spaces etc. etc.

I understand concerns about possible crash of spd itself, but this could be worked arround with dynamic loading and correctly handling error on spd side.
What you are saying about linking object with module files, this is what i am talking about, Developer should not be forced to use that approach. When i am developing module in rust, i shouldn't need to take half source tree of spd, module files use other parts of spd, and using another build system alone to build a module would result in taking parts of spd source tree.
You are saying about pushing audio, that would be possible to register a callback on side of speechd, and grabbing audio from there.
And in this case, we wouldn't need any plugin interface. Yes, for a reference, i could read a header file from i should implement, but really, no need to take it in rust, we could just export needed c-api in our library and that's all.

I understand concerns about possible crash of spd itself, but this could be worked arround with dynamic loading and correctly handling error on spd side.

No. When the function that you called segfaults, it's really difficult to recover. And there are loads of such issues that you get when sharing the process.

What you are saying about linking object with module files, this is what i am talking about, Developer should not be forced to use that approach.

What problem does this approach actually poses?

When i am developing module in rust, i shouldn't need to take half source tree of spd

You are talking about module_main.c module_readline.c module_process.c, not "half source tree". Again, we can stuff these in a library so that you just need to -lspeechd-module and be done.

and using another build system alone to build a module

Ok, then, again, let's go with the speechd-module library approach. That'll be a couple Makefile.am lines, instead of a whole plugin-loading and interaction with the speech server that will take ages to get right, and then add up to the maintenance.

You are saying about pushing audio, that would be possible to register a callback on side of speechd, and grabbing audio from there.

You're simplifying the problem. It's not just audio, it's also about events. I don't see how registering callbacks will be simpler than just calling a function. Really, really, really, does src/modules/module_main.h look all that complex?

And in this case, we wouldn't need any plugin interface. Yes, for a reference, i could read a header file from i should implement, but really, no need to take it in rust, we could just export needed c-api in our library and that's all.

And that's exactly what you can already do with  module_main.h.

Ok, i still stay on fact, that architecturally it would be better to reconsider what is now, but yes, i agree, that having module as statically and dynamically linked libraries exporting c-api would be better, and not depended on speechd at all, better having it as a separate project.