The proxy API is the one that we would like to expose for applications
and the other API is used internally when implementing modules or
factories.
The current pw_core object is really a context for all objects so
name it that way. It also makes it possible to rename pw_core_proxy
to pw_proxy later.
Also disconnect filters.
Ignore multiple destroy calls. This can happen when the protocol
destroys the core-proxy and some implementation cleanup code
does the same. The cleanup code can't reliably know about this
cleanup.
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 it possible to know when a proxy is bound to a global id before
the global shows up in the registry. This makes it possible to match
locally created objects to the one appearing in the registry and
possibly avoid a second bind.
Remove some of the unused states in pw_stream. The app can know the
state by following the format and buffer events.
Make it possible to be notified of io are updates. This should make it
possible to follow the transport etc.
Make it possible to be notified of any param changes.
Rename finish_format to update_params because that is what it does.
Make this work in the same was as the filter: updating the params
removes all old params of the types and installs the new ones.
Don't get the Props and PropInfo from the node proxy, instead get them
directly from the adapter that we have locally. Update the controls
directly on the adapter instead of going to the server first.
The filter API is meant for making generic audio and video filters.
It's like a pw_stream but with many in/out ports and no conversion.
Eventually the pw_stream will be implemented with the filter.
Add some example audio and video filters.
Change node.priority to priority.session to indicate that this
is the priority that the session manager uses to select the node.
Add another priority.master that the core uses to select a master
driver. Keep the driver nodes sorted by master priority.
Let jack always prefer to connect to the master driver nodes.
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.
When the port receives a format, look if we can find a mixer for it
and configure it.
Use the float32 mono mixer when possible.
Use the new pw_buffers in the link.
Let the port allocate buffers between the mixer and node when
requested.
The client-node doesn't need a mixer because mixing is done on the
client.
Remove all mixer and buffer negotiation code from adapter because
it is now done at the port level.
Remove the monitor API, we can use the device API for it. Make sure
we support creating devices (like alsa) from another device (udev).
Use new object.id to store the object id in the object properties. Use
the port.id/node.id etc to make relations to other objects.
Reorganize some things, let the clients update the segment info
in their own activation, then let the server merge it. This avoids
clients stepping on eachother. When looping through the clients,
copy the segment info when we encounter its owner.
Remove the list of segment owners to the activation. This is better
than in the activation because we can then just keep one list of
owners.
Remove the NONBLOCK flag from the eventfd so that we can do blocking
reads as well.
Just keep a reposition owner in the driver activation. This points
to the node that has the reposition info. This avoid complicated
synchronization to keep multiple nodes from stepping on eachother.
Now they can just prepare the reposition info in their activation and
set themselves as the reposition owner. The last one who succeeds
wins.
When the node latency property is changed, trigger a graph recalc
to set the new quantum if needed.
Also update the driver quantum when unassigned nodes are assigned
to a driver.
This makes it easier to keep track of who is responsible for what.
Also remove the valid fields and move them to flags in the segment
info. That way, the owner can update the flags without having to
worry about concurrency.
Keep separate info for the reposition information. We need to do this
to make it possible to seek in other formats than the frame.
Clear out the owner field when the node is destroyed or removed from
the driver.
Place the requested sync and position update flag in the node
activation. This way we can use our existing loop to update the node
sync states and check if the node is ready.
Implement sync timeout, when the client can't start or seek within the
timeout, we start RUNNING anyway and hope the client catches up.
Sync is enabled when clients need time to move to a new location.
It's a bit like GStreamer preroll after a seek. Clients that need
time, increment the sync_total. Whenever a seek is done, the server
waits in the Starting state until the sync_pending is 0 (or timeout
later).
Improve atomic operations
Add an offset to apply to the clock time before we can compare to the
segment values. This way we can keep the segment start independent of the
clock values and we only need to adjust the offset when paused. It's
like the base_time in GStreamer to calculate the running time.
Move fields from the io_position to io_segment. The segment contains
the mapping between raw clock time and stream time in various
formats. We keep an array of pending segments available in the
io_position field so clients can anticipate changes.
Make looping a flag in the segment instead of a state.
Prepare for segment masters. These will be registered clients that
are responsible for updating parts of the extended segment info.
Add namespace to some defines.
Move some things around. Move the duration of the current cycle
to the clock. Also add the estimated next timeout to the clock.
Add a generic media specific counter to the clock.
Clean up the position_bar info. We can do with only a double beat
value and make the signature in floats.
Flesh out the io_position info. This has now the information needed
to convert a raw clock time into a stream time. It basically has
the same kind of features as GStreamer segments such as looping,
variable rate playback etc.. It also contains the state of the
timeline (paused/playing) and it can be used to update the position
and state from clients.
There is also extended information in the position field that
clients can update when they can.
Plugins basically only update the clock info they get (and use
the position info to check if they are slaved or not).
Before each cycle, check if there is a pending position update and
apply it.
Add flag to always assign a node to a driver. This makes sure that
even when the node is not linked to anything, it will still be
scheduled by an active driver. This is needed for JACK support.
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.
Implement per channel volume on channelmix. Extend control on stream to
take an array of values when possible.
Remove name argument from pw_node_new and pw_device_new. We can pass
this as a property instead.
Improve properties on nodes to more closely match what pulseaudio does.
Don't let the monitor do too much with the udev properties but let the
session manager set the description and icon-names.
Remove some change_mask flags for things that don't change in
introspect. Use the flags to mark changes in -cli and -monitor.