The pw_remote object is really a wrapper around the pw_core_proxy.
The events it emits are also available in the core proxy and are
generally awkward to use.
With some clever new pw_core_proxy_* methods and a pw_core_connect
to create the core_proxy, we can convert all code away from pw_remote.
This is a first step in this conversion, using the pw_remote behind
the scenes. It leaks into some places because it really needs to become
its own struct in a next step.
Make the connection as soon as we create the client. We create it
without file descriptor and then set it when we connect. This
makes it possible to use the connection to queue messages before
we connect.
Don't register in client_new() to make it possible to do other things
on the client before registering. Register the client in protocol-native
after we set up the events etc.
otherwise, if the access module blocks the client, the on_start
callback in the protocol is not called and there is no global,
which means the session manager cannot do anything to grant
permissions on this client and the client is blocked forever
Separate the session manager in a monitor and policy part.
The monitor manages the devices and endpoints.
The policy watches the nodes/ports/clients and applies the policy
of linking them.
Because both now have a separate connection, we can remove some
hacks in the protocol. When a remote was both the implementer and
user of an object we could get in a deadlock when the user was
blocked waiting and the implementator was blocked sending a reply.
We used to un-busy a client when it was expecting a reply from a
ping or sync for this reason.
Add and use some more keys for the endpoints and streams.
For flatpaks we need to be able to support older v0 protocol clients.
To handle this we have:
- the connection detects an old client when it receives the first
message. It can do this by checking the sequence number, on old
versions it contains the message size and is never 0, on new
clients the sequence number is 0.
- We add a new signal at the start of the connection with the detected
version number. This installs the right version of the core proxy.
We also move the binding of the client until the hello message is
received. This way we can have a new client connect (portal),
hand over the connection to an old client, which then removes the
client binding again in the hello request with a v0 version.
There are some changes to the passing of fds in v0 vs v3 which need
to investigated some more.
- bump version of our interfaces to 3. This makes it possible to
have v0 and v3 protocol marshal functions.
- Add version number in the proxy. This is mostly automatically done
internally based on the version numbers the library is compiled
with. Where the version number was in the API before, it is now
actually used to look up the right protocol marshal functions. For
Proxies there is usually just 1 version, the current one. It is the
server that will support different versions.
- Add v0 compat marshal functions to convert from and to v0 format.
This has some complications. v0 has a type map it keeps in sync
with the server. For this we have a static type map with mappings
to our own v3 types. Pods are mostly the same except for objects
that used to have arbitrary pods in v0 vs spa_pod_prop in v3. Also
convert between v0 spa_pod_prop and v3 spa_pod_choice.
Formats and commands are also slightly different so handle those
mappings as well.
We only have marshal functions for the server side (resource)
v0 functions.
- Add v0 compatible client-node again. It's a bit tricky to map, v0
client-node basically lets the server to the mixing and teeing
and just does the processing of the internal node.
After we grab the lockfile we should remove the socket when it
exists so that we can bind again. This should solve startup
problems after a crash, which left the socket around and caused
bind failures.
Getting SO_PEERSEC on distributions that do not use a LSM by default,
results always in a "protocol error", which is just annoying and not
a real problem for pipewire's operation.
Remove the parent_id from the global event. Remove the parent
and owner from the global object.
Use properties instead to mark parents and owners of objects.
Properties are easier to control for client exported objects and
usually a simple parent/child is not enough. For example, a client
exported node has the client as a parent but also the factory that
created the node.
When we destroy a proxy, mark it as zombie until the server removes
the id. This way we can still keep the id locked with a valid entry
and remove it later.
Make pw_remote_connect_fd() not automatically close the provided
fd but let the caller take care of that. This allows us to reuse
the fd in pipewiresrc.
Fixes#155
Move the epoll functions to the system functions and make the loop
use those. Use simple mask for events instead of enum.
Add the used system api in pw_loop.
Add System API to spa_support and use it where possible.
Pass the system API used in the realtime loops in spa_support as
well and use this in the realtime paths.
Improve bootstrapping, load only the log and cpu interfaces because
those can/need to be shared between instances. Let the core load
the other interfaces.
Add keys to configure the System and Loop implementations used in
pw_loop.
The interface struct has the type,version and methods of the
interface.
Make spa interfaces extend from spa_interface and make a
separate structure for the methods.
Pass a generic void* as the first argument of methods, like
we don in PipeWire.
Bundle the methods + implementation in a versioned inteface
and use that to invoke methods. This way we can do version
checks on the methods.
Make resource and proxy interfaces that we can can call. We
can then make the core interfaces independent on proxy/resource and
hide them in the lower layers.
Add add_listener method to methods of core interfaces, just
like SPA.
Don't pass the ucred to the client construct, just set the properties
in the protocol.
Use the client properties to get ucred.
Add the security label to the client properties (from SO_PEERSEC)
Pass a message around to make things more extensible later.
Keep fds per message if we ever want to write individual
messages.
Pass number of fds in the message header. We might need this to
close the fds when the proxy is gone.
Don't use special callback in node to receive the results. Instead,
use a generic result callback to receive the result. This makes things
a bit more symetric and generic again because then you can choose how
to match the result to the request and you have a generic way to handle
both the sync and async case. We can then also remove the wait method.
This also makes the remote interface and spa interface to objects very
similar.
Make a helper object to receive and dispatch results. Use this in the
helper for enum_params.
Make device use the same result callbacks.
Remove the done and error callbacks. The error callback is in an
error message. The done callback is replace with spa_pending.
Make enum_params take a callback and data for the results. This allows
us to push the results one after another to the app and avoids ownership
issues of the passed data. We can then extend this to handle the async
case by doing a _wait call with a spa_pending+callback+data that will
be called when the _enum_params returns and async result.
Add a sync method.
All methods can now return SPA_RESULT_IS_ASYNC return values and you
can use spa_node_wait() to register a callback when they complete
with optional extra parameters. This makes it easier to sync and
handle the reply.
Make helper methods to simulate the sync enum_params behaviour for
sync nodes.
Let the transport generate the sequence number for pw_resource_sync()
and pw_proxy_sync(). That way we don't need to keep track of numbers
ourselves and we can match the reply to the request easily.
Add return values to events and method callbacks. This makes it
possible to pass any error or async return value.
Add sync/done/error in both directions so that both proxy and resource
and perform/reply sync and produce errors.
Return a SPA_ASYNC from remote method calls (and events), keep the
sequence number in the connection.
With the core sync/done we can remove the client-node done method and
it's internal sequence number along with the seq number in method calls.
We can also use the method/event async return value to perform a sync
with as the unique sequence number for this method.
Add sync method and done/error event to proxy and resource.
Make some more varargs error functions
Make pw_resource_error always just send the error to the resource id.
Make sure we send errors to the right destination.
Add proxy error event and emit it when the core finds an error for
the given proxy id.
The client error is supposed to be sent to all resources of a client
for the given global.