-
Notifications
You must be signed in to change notification settings - Fork 2.9k
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
ao_sndio: add this audio output again #8314
Conversation
9d0b034
to
48cfb22
Compare
There is something wrong with channel mapping: 6 channels some times like mono. |
It was always marked as "experimental", and had inherent problems that were never fixed. It was disabled by default, and I don't think anyone is using it.
I'm currently doing a bit of a different approach in https://github.com/ericonr/mpv/tree/sndio , and should probably PR it for discussion, then. |
I do not use sndio so feel free to continue development :) At this time there is 2 known for me issues:
|
Re. 1, I can definitely test it. I didn't do anything with fast rewind, only pause-play and seeking. Re. 2, I will look into it. I will open a PR with my version as an alternative to this one, hopefully the maintainers can take a look and decide what they prefer. |
Yes, I mean seeking, but with mouse wheel scrolling. |
48cfb22
to
c3351a7
Compare
Has been working fine. |
Thank you for your work!
I couldn't reproduce it. Maybe I was doing something wrong. |
Possible that this is some problem with sndio wrapper on FreeBSD. |
You two seems to know sndio better than current maintainers, and we clearly cannot take more than one version, so I think it would be best for everyone if you two @ericonr and @rozhuk-im could join forces and produce together only one version (it does look like both of you also comment on eachother's PR, so you're already halfway there? ;) ). |
@avih Before this week even sndio wrapper was not installed on my system :) IMHO, for now, better to merge this PR: it is good base to continue improve code and add features. |
I can ask around, but I don't think the issue with requiring a device reset (and possibly disconnect and reconnect) was ever spotted, since the previous code never did anything like that. Does it make sense to add this code, since it's apparently (there could be people having this issue, they just didn't speak up) only for the FreeBSD version of sndio? |
c3351a7
to
6ff8190
Compare
e7f0274
to
f395745
Compare
audio/out/ao_sndio.c
Outdated
if (!p->pfd) | ||
goto err_out; | ||
|
||
ao->device_buffer = p->par.appbufsz; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this needs to be p->par.bufsz
. sndio won't start playing until bufsz is filled (see this recent clarification in the manual: https://marc.info/?l=openbsd-tech&m=160650041114362&w=2), and since appbufsz < bufsz, it never starts playing for me.
Or maybe, this should be left at appbufsz, and we should use p->par.bufsz
instead of ao->device_buffer
when calculating free_samples
below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With p->par.bufsz
does not work: GUI/Video freezes, looks like write()
block, but sound - ok.
As I understand appbufsz
- buf size available for unblocked write, and it can be set. bufsz
- R/O internal allocated memory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am testing your PR, but sound does not play for me, it just hangs at 0:00. This is because the buffer is never filled up to bufsz, so sndio never starts draining the buffer.
If I change line 301 (state->free_samples
) to use p->par.bufsz
, or if I change this line to use p->par.bufsz
, the issue goes away.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
p->par.appbufsz = ((p->par.rate * 80) / 1000); /* 80ms buffer. */
can you try increase it to 800?
ao->device_buffer = p->par.bufsz / 2;
- work for me, is ~82ms, so looks like it > appbufsz.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I set ao->device_buffer
to p->par.appbufsz + p->par.round
- 85,3ms still works.
I suspect that shdio wait to fill appbufsz
and then starts, at least on OpenBSD, but FreeBSD wrapper starts after first sio_write()
.
ao->device_buffer = p->par.appbufsz + p->par.round;
- probably will allow both sndio implementations work.
d26b2c4
to
6a57a29
Compare
I've been doing some testing with the three sndio PRs (@rozhuk-im push 9e3ae91 and 0ef7db7, @ericonr push, @ericonr pull), and I think I'm starting to understand some of the issues here. I'm on Linux using sndio via alsa, both with sndiod (
There was a recent clarification in the manual saying that we need to write up bufsz frames before playback starts: openbsd/src@b710ff0 In my testing, audio seems to start playing exactly when appbufsz samples are written, but these aren't reported via onmove until we start to write more samples (not sure about the exact number). This causes us to think the buffer is full and stop writing samples, resulting in a hang after the first block is played. If the start of the file is silent, this sounds like it just hung immediately. In all cases I tested,
I believe this is caused by /* Do actual reset only on errors. */
if (p->playing)
return; During seek, mpv calls I don't think the reset can be avoided like you are trying to do. @ericonr's push version does a full I think the main decision we need to make is whether to go with a push-based or pull-based design. With push-based, the root of the problem seems to be that mpv's push API expects us to be able to tell it how many samples can be written without blocking, which is at odds with sndio's semantics:
However, it seems like it mostly works with With a pull-based design, there is less to worry about. @ericonr's current pull version still does blocking writes, but I think this only affects cancellation (and it could be made to use non-blocking I/O). I am currently thinking the pull-based version (#8347) is the right way to go. My only concern is that sndio may be playing over the network, and since pause is emulated by silence, there will be continuous network activity when paused. Either way, it is probably a good idea to get some feedback from sndio developers to make sure we're on the right track.
With 9e3ae91 the audio always starts, but I occasionally see hangs on seeks. It happens fairly often with rsnd, and sometimes it also hangs when resuming from pause. With snd, if I increase the sndiod buffer size I also get hangs on seeks. If I leave the sndiod buffer size at the default, I get the choppiness described by @noiseless. I think this is just because the buffer size (20ms) is too small. With 0ef7db7 the audio does not start with sndiod, but does start with rsnd, and does not seem to hang when seeking or pausing. |
It just hides that writes some times blocked from mpv code. I look into sndio-oss wrapper lib, I can make ideal mpv sndio backend for this, but IMHO this wrapper in some parts does not respect sndio API behavior that described in sndio manual. |
With these changes:
Hope this will work in most sndio implementations. @noiseless , @michaelforney if you have time, please test. |
Now (35e8fa3) playback also starts immediately, but the sound is still not continuous. At the same time, I can say that the frequency of audio interruptions has become higher, and the pauses between fragments of the audio track are shorter, which makes the overall sound better (but still not as it should).
|
I don't quite understand what you mean here, could you try rephrasing? The push API relies on
With the default sndiod buffer and block size ( If I modify your PR with - ao->device_buffer = p->par.appbufsz;
+ ao->device_buffer = p->par.bufsz; it seems to fix both problems, and works with sndiod and raw device access. |
https://sndio.org/tips.html#section_10_2 also mentions that using |
With the patch from @michaelforney, I no longer see any problems with the sound. Everything works. Thanks! |
Remove pause: reset + start do same. Hope this fix issues from prev messages. |
Built mpv with 1ff2838. |
Is there any hope that the code will be accepted into the main branch? I use mpv with this patch and everything works for me (OpenBSD current + mpv 0.33.0). |
Works fine with Artix Linux too (mpv 0.33.0). |
Changes: - rewrite to use new internal MPV API; - code refactoring; - fix buffers size calculations; - buffer set to auto; - reset() - clean/reinit device only after errors;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I found a bug
EDIT: Oh wait, left to right, so this isn't actually an issue. NEVERMIND
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Carrying over some comments from @ericonr's closed pull request that also apply here.
if (!sio_getpar(p->hdl, &p->par)) { | ||
MP_ERR(ao, "couldn't get params\n"); | ||
goto err_out; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to adjust the ao
fields to match the negotiated parameters here. If the sndio device only supports certain channel counts and sample rates, it may not choose the preferred parameters and conversion is needed.
I noticed this when testing with a USB DAC that only supports 2 channels and certain sample rates when trying to play files with strange sample rates or that are mono or 5.1. It would stall or underrun because mpv and sndio end up using different parameters.
I think the following should be sufficient:
/* use negotiated parameters */
ao->samplerate = p->par.rate;
ao->channels = sndio_layouts[p->par.pchan];
ao->format
is already taken care of below.
p->havevol = sio_onvol(p->hdl, volcb, ao); | ||
sio_onmove(p->hdl, movecb, ao); | ||
|
||
p->pfd = calloc(sio_nfds(p->hdl), sizeof(struct pollfd)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most of mpv uses talloc for allocation.
p->pfd = talloc_array_ptrtype(p, p->pfd, sio_nfds(p->hdl));
You don't have to worry about freeing it or checking for errors since it gets freed automatically when p
does, and it aborts on failure.
}; | ||
|
||
|
||
static const struct mp_chmap sndio_layouts[MP_NUM_CHANNELS + 1] = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why MP_NUM_CHANNELS + 1
instead of just using the implicit array size (sndio_layouts[]
)?
p->par.bps = ap->bits / 8; | ||
break; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This loop could be restructured a bit to be simpler:
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;
break;
}
}
p->par.sig = ap->sig; | ||
if (ap->bits > 8) | ||
p->par.le = SIO_LE_NATIVE; | ||
if (ap->bits != SIO_BPS(ap->bits)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As @ericonr pointed out in his PR, this condition doesn't make sense. It's comparing a number of bits to a number of bytes, so it is never false. I'm curious what the intention was in the original code.
Anyway, I think you can just remove it. The sndio docs say the default for bps
is "the smallest power of two large enough to hold bits", which is exactly what we want.
ao_sndio: add this audio output again: mpv-player/mpv#8314 From Brad
I should mention, that mplayer added something in one of their versions, as did smplayer to fix the video a/v problem... the desync issues in mp4 video/audio files. i am not sure if smplayer and mplayer use the same solution, also, smplayer can use mpv instead of mplayer, and mp4's run flawlessly, thanks to a certain option, I mentioned it as a possible fix: It would be nice if this fix could be directly implemented into mpv even if its an optional command which only happens when sndio is enabled. Hyperbola is one of a few linux distros with sndio as their main audio. I recall artix and devuan had sndio at one point, not sure if they still do. |
I put this into our OpenBSD package for the last 3 weeks but there are some issues with the backend as is. The feedback we received was... "The loop function in mpv stopped working in the last two weeks. If it reaches the end of a file it stops playing. If I use the 'l' key to mark certain parts of a track, it stops playing at and "I tested mpv-0.3.11p1 and twitch.tv livestreams with youtube-dl have a |
I'm not sure if this is a problem with mpv and/or sndio. I've never used twitch, but I checked youtube live streams - I couldn't reproduce the error. I am using mpv 0.33.1 with this patch on OpenBSD-current and yt-dlp instead of youtube-dl. A randomly selected livestream on youtube is simply played, after pressing "play/pause" button - too. The other two, also randomly selected, are also simply played. It seems to me that either more information is needed here about the way to reproduce the problem; or it should be looked for elsewhere, not in the mpv. UPD: I checked the same streams from youtube-dl - the problem also does not reproduce. Probably need more information and/or examples. |
I can confirm it. The problem exists and is trivially reproduced. |
The problem goes away when just switching the audio backend. |
I'm sorry, I missed a message in the mailing list with examples of problems. For the history:
(source) I managed to reproduce the problem, however, with a different channel (the channel from the example is not available), but it does not matter. |
Apparently, I fixed the problem and returned the behavior of the sndio backend to what it was in mpv 0.32. If I don't find any new problems, I will publish a patch and/or pull request later tonight (MSK). |
Changes: * fixed hangups in the loop function and in some other cases * refactoring according to @michaelforney's recommendations in #8314 * a few minor and/or cosmetic changes * ability to build ao_sndio using meson
Changes: