Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ao_sndio as pull driver #8347

Closed
wants to merge 4 commits into from
Closed

Conversation

ericonr
Copy link
Contributor

@ericonr ericonr commented Nov 30, 2020

If we are striving for the least amount of code to maintain, I believe a pull driver is the way. It requires launching a thread inside the backend, but nothing too complicated.

This is an alternative for #8320 and #8314 . I'd be ok with closing #8320 in favor of this PR.

@rozhuk-im what do you think of this solution?

Changes from previous version:

- Use a local buffer for write() calls that happen before start(), since
sndio doesn't have an API for pause and can't take writes unless it's
been started. Calling sio_start() will make it start playing as soon as
the buffers are full, so the sio_write() loop in start() doesn't
introduce any noticeable latency.

- Allow libsndio to pick a buffer size by itself.

- Allow core to emulate pause with reset().
* using a multiple of block size */
to_write = ((ao->device_buffer - p->delay) / p->par.round) * p->par.round;
/* time until buffer is heard is: (<current sample delay> + <new samples>) / <sample rate> */
n = ao_read_data(ao, data, to_write, mp_time_us() + ((p->delay + to_write) * 1000000LL) / p->par.rate);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Would it be okay to add a macro for 1000000LL in osdeps/time.h ?

@rozhuk-im
Copy link
Contributor

It works.
No freezes on seeking.

But, if in #8314 I remove pause() and make reset() empty - I got same effect, and code is more compact.
Also, if no reset()/pause() then on pause it continue play from buffer.
Default sndio buffer in FreeBSD wrapper is 200ms.

@ericonr ericonr force-pushed the sndio-pull branch 2 times, most recently from da69907 to 0903658 Compare December 1, 2020 22:19
@ericonr
Copy link
Contributor Author

ericonr commented Dec 2, 2020

Also, if no reset()/pause() then on pause it continue play from buffer.

Yes, mpv feeds it silence. Currently, the jack backend does the same thing. I like the pull driver because it gives mpv the most information possible while at the same time simplifying pause.

@rozhuk-im
Copy link
Contributor

I like the pull driver because it gives mpv the most information possible while at the same time simplifying pause.

Via ao_read_data() pull sndio backend report only about free buf space and some time. This is 2 params.
Via ```get_state() push sndio backend (#8314) - 4 parameters passed.

Current push sndio backend (#8314) has no pause() callback, what can be more simple? :)

@ericonr
Copy link
Contributor Author

ericonr commented Dec 7, 2020

@rozhuk-im

Via ```get_state() push sndio backend (#8314) - 4 parameters passed.

Yes, but 4 parameters which aren't entirely necessary. The only information that mpv needs is latency, and if we can take care of the rest inside the driver, it's much simpler. And it's the "best quality" latency information that we can give, as well.

@noiseless could you try this one out as well?

Copy link
Contributor

@michaelforney michaelforney left a comment

Choose a reason for hiding this comment

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

Did some more testing and noticed an issue with parameter negotiation.

Also added a few style comments. Feel free to ignore the ones you disagree with.


sio_initpar(&p->par);
for (i = 0, ap = af_to_par;; i++, ap++) {
if (i == sizeof(af_to_par) / sizeof(struct af_to_par)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

You could use MP_ARRAY_SIZE(af_to_par) here.

Or better yet, how about this instead:

    sio_initpar(&p->par);
    p->par.bits = 16;
    p->par.sig = 1;
    p->par.le = SIO_LE_NATIVE;
    for (i = 0; i < MP_ARRAY_SIZE(af_to_par); i++) {
        ap = &af_to_par[i];
        if (ap->format == ao->format) {
            p->par.bits = ap->bits;
            p->par.sig = ap->sig;
            if (ap->bits > 8)
                p->par.le = SIO_LE_NATIVE;
            if (ap->bits != SIO_BPS(ap->bits))
                p->par.bps = ap->bits / 8;
            break;
        }
    }

I don't think the message about format conversion is necessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's a bit cleaner, but I think

            if (ap->bits > 8)
                p->par.le = SIO_LE_NATIVE;

is unnecessary? Since it's set to SIO_LE_NATIVE by default.

The

 if (ap->bits != SIO_BPS(ap->bits))
                p->par.bps = ap->bits / 8;

is weird to me as well, since it's comparing a number of bytes with a number of bits.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That last block was in the original code as well, which is quite interesting.

audio/out/ao_sndio.c Outdated Show resolved Hide resolved
audio/out/ao_sndio.c Show resolved Hide resolved
audio/out/ao_sndio.c Outdated Show resolved Hide resolved
audio/out/ao_sndio.c Outdated Show resolved Hide resolved
audio/out/ao_sndio.c Outdated Show resolved Hide resolved
audio/out/ao_sndio.c Outdated Show resolved Hide resolved
audio/out/ao_sndio.c Outdated Show resolved Hide resolved
@noiseless
Copy link
Contributor

@ericonr

I'm sorry I missed your message. I will try to test it tonight (MSK).

@noiseless
Copy link
Contributor

Built mpv with your patch (0903658). I didn't notice any problems, everything works as expected.
OpenBSD-current, mpv 0.33.0 + patch.

@ericonr ericonr force-pushed the sndio-pull branch 3 times, most recently from e9aa1a2 to 2b54c75 Compare December 10, 2020 05:19
@ericonr
Copy link
Contributor Author

ericonr commented Dec 10, 2020

@noiseless thank you very much for testing :)

I've updated the PR and it should now be more correct for channel mappings.

audio/out/ao_sndio.c Outdated Show resolved Hide resolved
audio/out/ao_sndio.c Outdated Show resolved Hide resolved
audio/out/ao_sndio.c Outdated Show resolved Hide resolved
@michaelforney
Copy link
Contributor

I took a stab at making it use non-blocking I/O here:
ericonr/mpv@sndio-pull...michaelforney:sndio-pull-nonblock

I think the only real advantage it has over your current version is that if our estimate of how much to write was wrong (sndio manual says "Note that sio_write() might block even if there is buffer space left"), it moves into a cancellable state rather than blocking in sio_write.

Removes some complexity, since the pull interface is much simpler.
Also fix some weird parts in the previous backend.

Allow libsndio greater control over most of the parameters.

Thanks to @michaelforney and @rozhuk-im for suggestions and @noiseless
for testing.
@ericonr
Copy link
Contributor Author

ericonr commented Dec 11, 2020

I think the only real advantage it has over your current version is that if our estimate of how much to write was wrong (sndio manual says "Note that sio_write() might block even if there is buffer space left"), it moves into a cancellable state rather than blocking in sio_write.

I don't think it would block for long; we are writing at most device_buffer, and any errors there should make it exit on its own. And using a separate thread for driving sndio is mostly to allow us some freedom in blocking if necessary.

Being in a cancellable state more often could be useful if there are cases where bufsz is big (lots of latency) and quitting the application takes too long. The UX could then be improved (perhaps?) by not allowing a big write to happen. I'm unsure if your impl would allow for that.

@brad0
Copy link
Contributor

brad0 commented Dec 18, 2020

Any update on this? There is no longer any sound support for OpenBSD with 0.33.

@brad0
Copy link
Contributor

brad0 commented Jan 31, 2021

ping.

1 similar comment
@brad0
Copy link
Contributor

brad0 commented Feb 28, 2021

ping.

@brad0
Copy link
Contributor

brad0 commented May 5, 2021

Any chance of seeing this commited?

@ericonr
Copy link
Contributor Author

ericonr commented May 7, 2021

This is not the right way forward, because sndio's mixing depends on the amount of active sources. Pausing a video here will still make the daemon think the source is active, and therefore other sources will be a bit more muted. It's necessary to use sio_stop and sio_start to implement a well behaved sndio client.

@ericonr ericonr closed this May 7, 2021
@lanodan
Copy link

lanodan commented Jul 22, 2021

I don't know for others but I think it would be better to have a "good enough" audio backend in mpv that could get heavily modified later than the current situation where it's either no audio at all or having to use compat-layers like alsa-sndio which probably are doomed to be worse than an okay driver (for example the lack of volume integration).

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.

6 participants