Last active
January 21, 2021 13:28
-
-
Save namandixit/fb4df2862a5b4be817b68d7d841a2fe3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* NOTE(naman): Description of current Audio system. | |
-------------------------------------------------------------------- | |
We have two positions inside the audio buffer: play_cursor and | |
write_cursor. The play_cursor signals what bytes are currently | |
being played by the audio hardware (well...) while the write_cursor | |
signals where in the audio buffer is it safe to write new data. | |
MSDN says that write_cursor is usually ahead of the play_cursor | |
by about 15 ms. As the audio gets played, both these positions | |
slowly move forward (and wrap around when they reach the edge | |
of the audio buffer). | |
------------------------------------------------------------------- | |
Now, there are two parameters that effect our audio: | |
1. (write_cursor - play_cursor): The difference between the | |
two positions indicates the latency of our audio system. | |
Since we will be writing after the write_cursor, any new data | |
that we write will get played after the time indicated by | |
the difference in the two positions. | |
2. Difference between two back-to-back positions: This indicates | |
responsiveness of the sound system. If we find the difference | |
between the write_cursor (or play_cursor) of this frame and the | |
one of the last, we can hit upon two cases: | |
i) The difference is zero: The cursors are actually not hardware | |
variables. This means that they might have very low resolution and | |
increment only once in a while. The time between two changes | |
in the value of cursors could even be more than a frame time. | |
ii) The difference is non-zero: At this point, the cursors have | |
finally moved. However, because the cursors might have such low | |
resolution, we can not be sure that play_cursor actually indicates | |
the position where the audio is being played. Instead, the cursors | |
would only give a rough approximation of what sound might actually | |
be playing. Also, because of the low resolution, the difference | |
might be very high, higher than a frame time. | |
------------------------------------------------------------------- | |
High latency would mean that the audio that we write -- that corresponds | |
to the video image that is going to be displayed at the upcoming | |
frame flip -- will actually play some time after the video image has been | |
displayed. | |
Low latency would mean that if we were to write the audio data at | |
the write_cursor, it might actually start playing before the | |
corresponding video image has appeared on the screen. In this case, | |
we need to figure out what position in the sound buffer would | |
correspond with the frame flip and write the audio data there. It also | |
means that if we spend too much time between querying for the | |
cursors and actually writing the data, the play_cursor might | |
catch up to or leave behind the cached write_cursor that we queried. | |
Low responsivness means that our write cursor might jump ahead | |
of the position in the sound buffer until where we have actually | |
written the audio data. This would mean that we have to write data | |
into the part of audio buffer where it is technically not safe to write. | |
High responsiveness doesn't seem to have any problems. | |
TODO(naman): Make sure that this is actually true (regarding high | |
responsiveness). | |
------------------------------------------------------------------------ | |
So, what is to be done? Before we begin, let's compute some shit: | |
1. write_cursor_linear (add buffer size to write cursor if it has wrapped, | |
. treat it as write_cursor from now) (maybe) (use common sense) | |
2. latency = write_cursor_linear - play_cursor | |
3. frame_bytes (bytes to be written in any frame, find using frame rate) | |
4. target_cursor (the last byte to which we wrote last time, not valid on | |
. first frame) | |
5. bytes_until_flip (how many bytes should be written until the frame flip) | |
6. worst_responsiveness (biggest difference in two consecutive write_cursors | |
. ever seen) | |
7. get_ahead_coefficient = (worst_responsiveness / frame_bytes) + 1 | |
Okay, here's what needs to be done: | |
1. If sound has low latency, we might be able to get frame perfect audio. | |
. First see if the write_cursor lies beyond the frame boundary. | |
. (a) If it does, then the dream of frame perfect audio is just | |
. a dream. See if this is the first frame. | |
. [I] If it is, then start writing from (play_cursor + bytes_until_flip) and | |
. write frame_bytes audio data. | |
. [II] If it is not, then see if the target_cursor is ahead of the write_cursor. | |
. <i> If target_cursor is ahead of write_cursor, then write frame_bytes audio | |
. from target_cursor. | |
. <ii> If it's not, then write frame_bytes audio from write_cursor. We | |
. will have an audio skip here. | |
. (b) If the write_cursor is behind the frame boundary, there's hope! | |
. There's light! See if this is the first frame. | |
. [I] If it is, then CONGRATS! Write frame_bytes audio from (play_cursor + | |
. bytes_until_flip) and rejoice! Make merry! | |
. [I] If it is not, then there's everything is out of our hands. Our audio | |
. experience depends on what happened in previous frames, the ghosts of | |
. the past haunt all of us evermore. See if the target_cursor is ahead of | |
. the write_cursor. | |
. <i> If it is, then write frame_bytes from target_cursor. | |
. <ii> If not, write frame_bytes from write_cursor. There will be a skip. | |
. (Did someone say emotional rollercoaster?) | |
2. If it doesn't have low latency, then curse the poverty of our audience. | |
. Blade Runner was right! Anyway, see if this is the first frame ever. | |
. (a) If it is, see if write_cursor is behind the frame flip (it _might_ happen, | |
. high latency doesn't say how high). | |
. [I] If it is, then we can still get perfectly synced audio. Xenu surely | |
. smiles upon us! Write frame_bytes from (play_cursor + bytes_until_flip). | |
. [II] If it's not, just accept our fate. Write frame_bytes from write_cursor | |
. and drown our sorrows in our own tears. | |
. (b) If it is not the first frame, our past sins have caught up with us again. | |
. See if target_cursor is ahead of the write_cursor. | |
. [I] If it is, all is well. Just write frame_bytes from target_cursor. | |
. [II] If it's not, we are in deep sewers. There will definitely be | |
. a skip now. Get frame_bytes worth of audio data (or more if | |
. whatever lead to this dark end is bound to happen again) and | |
. write it from write_cursor, whereever it may be. All our | |
. hardwork will be ignored, like sweat in shower. Time to throw | |
. the towel. | |
At this point, if write_cursor is behind the target cursor but is within | |
some threshold of distance, multiple bytes_to_write with get_ahead_coefficient | |
to try to prevent the write_cursor from passing the target_cursor. | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment