No objection to your objection on my behalf. Eventually, this is not about the renderer as all of the required code needs to be implemented in the audio node and the audio listener.
Apart from that, the audio renderer must export the audio listener via a public getListener() method, so that the audio node can access the listener and query it for its assigned audio track’s master volume.
The listener will keep track of the track master volumes and provide this via a simple api extension, namely setTrackMasterVolume() and getTrackMasterVolume().
In the audio node, upon updateGeometricState() and play() and playInstance(), the master volume for the assigned track will be taken into account and the volume will be adjusted accordingly.
Basically like so:
float masterVolume = getRenderer().getListener().getTrackMasterVolume(getTrack());
float actualVolume = getVolume() * masterVolume;
where masterVolume is in the range of 0.0f (muted) to 1.0f (maximum volume).
And, yes, I have already implemented the feature and I have already begun to implement a test case for it. And, apart from the immature looks of it, it seems to be working just fine.
As for the test case, I have found that whenever audio nodes, regardless of whether they are played using playInstance() or play(), have not been attached to either the rootNode or some child node thereof, they will not be assigned a channel by the underlying audio renderer implementation. In case of playInstance()/playSourceInstance() this is correctly so, but in case of play()/playSource() this seems to be an error. And, looking through the code, I cannot imaging how this could ever be possible. As such, I have not been able to track down this issue to its root cause. However, by attaching the audio node to for example the root node will remedy that situation and the channel will be properly assigned by the audio renderer implementation. This basically means that whenever I play an audio node that has not been attached as a child to the scene graph, that node will always have a channel id of -1 during its updateGeometricState phase.
Apart from that, AudioNode#updateGeometricState will only update the location/position for audio sources that have been assigned a channel. While this seems to be ok, it might be an edge case or over optimization of some sort. Because of that, and, based on both the current listener position and the audio node’s position, longer playing positional sounds that are played using playInstance() might not be repositioned in space correctly.