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

Work around DAC bug causing pop noise when seeking DSD over PCM #578

Open
Wang-Yue opened this issue Jun 8, 2019 · 25 comments

Comments

Projects
None yet
2 participants
@Wang-Yue
Copy link
Contributor

commented Jun 8, 2019

During MPD's DoP playback, when seeking in a track, there will be a few click/pop/hiccup noise over essentially all USB DACs I have (either ESS or AKM based, either XMOS based or custom implementation).

Latest version of MPD on both Linux and Mac all presented the same issue.
A few other players has the same issue, such as Foobar2000.
Some players are free of this problem, such as JRiver media center, or HQPlayer.

After some investigation, having OS audio stack's Start/Stop call in Cancel() is sufficient to make those DACs produce the hiccups. Those DACs will always revert to PCM mode when Stop instruction is called. When Start is issued, it will detect again and found it to be a DSD stream, and revert to DSD again. The hiccup + pop noise happens during the DAC's mode switching.

I recommend a similar change be applied to ALSA as well.

Wang-Yue added a commit to Wang-Yue/MPD that referenced this issue Jun 8, 2019

@MaxKellermann

This comment has been minimized.

Copy link
Member

commented Jun 11, 2019

This is about a bug in some DoP-capable DACs, and not about a MPD bug, right?
If anything, then this demonstrates how bad the whole idea of DoP was, and why this bad kludge should be removed from MPD. Instead, people should use DSD directly.

@Wang-Yue

This comment has been minimized.

Copy link
Contributor Author

commented Jun 11, 2019

If anything, then this demonstrates how bad the whole idea of DoP was, and why this bad kludge should be removed from MPD. Instead, people should use DSD directly.

I don't believe so. native DSD is not supported on platform such as Mac, iOS, or various *NIX like systems (such as FreeBSD). On Linux it requires a kernel patch to support certain DAC's altsettings. On Windows it needs specific ALSA driver.

And this is just USB. On TOSLINK/COAXIAL/etc only DoP is supported.

In any cace, this is unrelated to the bug report. I personally hate DSD as it limits all DSP possibilities. None of the DAWs use DSD as underlying format. I believe if we get rid of DSD altogether, the world would become a better place. However this is also unrelated to the bug report.

This is about a bug in some DoP-capable DACs, and not about a MPD bug, right?

I would say most DoP capable DACs would switch from DSD mode to PCM mode and back during a Stop/Start cycle. I don't know if I should call it a bug or feature, because MPD's choice of using a larger buffer (0.5s in ALSA) and use Cancel() to stop and wipe the buffer and then restart, is beyond firmware developer's estimation on how we use their product. Usually in audio programming, especially in DAWs, software synthesizer, or live performance software, people choose a buffer as small as possible to reduce latency, and they don't need to wipe their ring buffer when doing things such as Cancel(). MPD's way of handling is reasonable, but I don't think other software programs do it that way.

@MaxKellermann

This comment has been minimized.

Copy link
Member

commented Jun 11, 2019

Your answer is confusing. First you argue that DACs do not support MPD's workflow ("beyond estimation"). Later you say that MPD is "reasonable". That's a slight contradiction.

It doesn't matter if "other software programs do it that way".
What matters to me right now is: is MPD's behavior correct?

The classification "bug in MPD" or "workaround in MPD for bug in DAC" is important to me.
If it's a bug in MPD, we can read the specification, see what's wrong in MPD and fix it according to the specification. So far, you havn't pointed me to such a specification.
If it's a bug in the DAC, there is no specification telling us what to do. But then we have a decision to make: should MPD support buggy DACs at all? Adding the workaround (i.e. disabling cancellation like your PR suggested, or using smaller buffers) means there are disadvantages for owners of non-bugged DACs (increased seeking latency and higher deadline pressure); that's a bad trade-off.
A workaround for a hardware bug must not hurt non-bugged hardware. Then I'd rather not support the bugged hardware, at all.

@Wang-Yue

This comment has been minimized.

Copy link
Contributor Author

commented Jun 11, 2019

If it's a bug in MPD, we can read the specification, see what's wrong in MPD and fix it according to the specification. So far, you havn't pointed me to such a specification.

Depends on how you interpret the official DoP spec, the spec recommends "In order to switch from DSD to PCM mode the receiver has to detect at least 1 single missing DSD marker byte in at least 1 channel." If the stream is completely stopped, there will be no data (the entire stream is missing), and it's up to your own interpretation if "at least 1 single missing DSD marker byte" applies in this case.

Other than that, official DoP spec does not define what a DAC should do when a DoP stream is stopped. So technically it's an undefined behavior. A DAC is not buggy if they opt to reverting back to PCM mode when DoP stream is stopped.

If it's a bug in the DAC, there is no specification telling us what to do. But then we have a decision to make: should MPD support buggy DACs at all?

As mentioned above, I inclined not to call DACs work in that way "buggy". DoP spec does not define what a DAC should do in this case.

What matters to me right now is: is MPD's behavior correct?
A workaround for a hardware bug must not hurt non-bugged hardware.

MPD is a real world application. If the majorities of DAC implementations works that way, it's better to support it. Right now, many of the DoP supported USB DACs are implemented via XMOS based chip, and official XMOS firmware works in that way (if the stream is stopped, the mode reverts to PCM).

If you read Linux kernel's /sound/usb/quirks.c you can see how messy it is to support DSD for all kinds of audio hardware. That's the burden a good software implementation to take.

A workaround for a hardware bug must not hurt non-bugged hardware. Then I'd rather not support the bugged hardware, at all.

As mentioned above, hardware work that way is not buggy, and there're many of them. Depends on their hardware implementation, some will produce an audible noise, and some use electric switch to mute the sound when this happened, and the noise is less audible but there's a gap of silence when this happens.

Also, if the user is using a 'native' DSD capable device, and if their kernel support their device's altsettings, there's high chance DoP is not enabled when playing DSD. Those users are not affect by this workaround as well.

@MaxKellermann

This comment has been minimized.

Copy link
Member

commented Jun 11, 2019

Depends on how you interpret the official DoP spec, the spec recommends "In order to switch from DSD to PCM mode the receiver has to detect at least 1 single missing DSD marker byte in at least 1 channel." If the stream is completely stopped, there will be no data (the entire stream is missing), and it's up to your own interpretation if "at least 1 single missing DSD marker byte" applies in this case.

Now read the preceding sentence in the spec: "In order to switch from PCM to DSD mode the receiver has to detect 32 consecutive DSD marker bytes on all channels used."

At the time the DAC is restarted (after a cancellation), its ring buffer contains at least one period worth of audio data. I think we agree that this period always contains more than 32 consecutive DSD marker bytes on all channels used. This means there is always enough data to switch to DSD, and a DAC must (at the start of playback) never play DoP as PCM.

Clearly, your DAC does not implement this requirement properly! Therefore, the noise produced by your DAC is a DAC bug, because it does not implemented DoP properly.

Other than that, official DoP spec does not define what a DAC should do when a DoP stream is stopped. So technically it's an undefined behavior. A DAC is not buggy if they opt to reverting back to PCM mode when DoP stream is stopped.

This is misleading: of course, a DAC may revert back to PCM in that case, but your fallacy is that this not relevant. Because it must switch to DoP/DSD whenever there are 32 or more DoP marker bytes. Your DAC fails at this.

As mentioned above, I inclined not to call DACs work in that way "buggy". DoP spec does not define what a DAC should do in this case.

Yes, it does.

MPD is a real world application. If the majorities of DAC implementations works that way, it's better to support it.

Are you changing the subject from "DoP specification" to an anecdote about "most DACs are buggy and MPD should support buggy DACs"? We may (or may not) agree on supporting buggy DACs, but right now I want to evaluate what your issue is about.

Right now, many of the DoP supported USB DACs are implemented via XMOS based chip, and official XMOS firmware works in that way (if the stream is stopped, the mode reverts to PCM).

Again, that's not relevant. Reverting to PCM is perfectly fine, but not switching to DSD within the constraints described in the DoP spec is a bug.

If you read Linux kernel's /sound/usb/quirks.c you can see how messy it is to support DSD for all kinds of audio hardware. That's the burden a good software implementation to take.

What is your argument here? That there exists some code in the Linux kernel telling anecdotes about hardware bugs?

Also, if the user is using a 'native' DSD capable device, and if their kernel support their device's altsettings, there's high chance DoP is not enabled when playing DSD. Those users are not affect by this workaround as well.

That completely misses the point.

@Wang-Yue

This comment has been minimized.

Copy link
Contributor Author

commented Jun 11, 2019

Let's check if we're on the same page:

first of all, let me clarify that that my DACs (or many other DACs, including all XMOS based ones) never plays DoP as PCM after restarting. After restarting it stays DoP mode all the time.

The problem happens during the restarting process, (which is a Stop plus a Start) the DAC can revert back to PCM mode during Stop and enter into DoP mode again during Start, because there's no spec forbidding it doing that, and I assume you agree on that? (based on what you said --- "of course, a DAC may revert back to PCM in that case")

What I say is, a restart like this will very likely produce audible glitch, and this is specified in many DAC chips' datasheet (you can refer to, for instance AKM chips' datasheet), that when a DAC chip restart, it will produce an audible pop sound. In this case, a hardware implementation can only do one of the two things

  • Just do nothing and let the pop noise be there
  • Use some hardware (such as an electric switch) to mute the sound, so the pop noise won't be heard. However this creates a gap

And these behaviors are not against any specs --- after all you are restarting a stream, and pop noise or pause could happen. The latter behavior is what AKM datasheets what recommends.

In terms of what software should do, It's best that software implementation is aware of that this may happen in the majority of DACs, and the best way to avoid the glitch (either a pop noise or a gap) is to avoid a start/stop cycle.

@MaxKellermann

This comment has been minimized.

Copy link
Member

commented Jun 11, 2019

The problem happens during the restarting process, (which is a Stop plus a Start) the DAC can revert back to PCM mode during Stop and enter into DoP mode again during Start, because there's no spec forbidding it doing that, and I assume you agree on that? (based on what you said --- "of course, a DAC may revert back to PCM in that case")

True, the DAC may revert back to whatever it wants if it's stopped. I'm not sure if any spec forbids the DAC to produce audible noise, but even without a spec, doing so is what I consider a "bug".

Now if the DAC firmware developers know that there is this bug which can produce noise (apparently they even documented this bug) - they could easily work around this by not reverting to PCM after a restart; they could wait until they are sure enough that the following data is really PCM and not DoP or DSD.

I don't grasp why those DAC firmware developers failed take this obvious workaround which would solve a good amount of this bug's symptoms. Instead, now every sound playing application needs to have a workaround which degrades the playback quality (for all users, not just those with buggy DACs).

This whole thing really isn't about whether the DoP spec allows reverting back to PCM; this is not specified and just doesn't matter, MPD shouldn't care about this DAC implementation detail.
What matters is that the noise-producing DAC bug exists, even though 100% of what affects MPD's Cancel() method could easily be worked around in the DAC firmware.

@Wang-Yue

This comment has been minimized.

Copy link
Contributor Author

commented Jun 11, 2019

Instead, now every sound playing application needs to have a workaround which degrades the playback quality (for all users, not just those with buggy DACs).

The PR I propose only changes DOP behavior. This is because the majority of DACs are “buggy”. It doesn’t change PCM nor native DSD playback.

worked around in the DAC firmware

Yes. It is better if firmware work in the way you were suggesting. But usb interface chips suppliers (such as XMOS)’s reference code does not. DAC manufacturers just use the reference code with little modifications to underlying logic. In addition people with existing hardware rarely have firmware update support. So the problem is pervasive.

I'm not sure if any spec forbids the DAC to produce audible noise, but even without a spec, doing so is what I consider a "bug".

Technically, if you stop the dac, wipe its buffer (by using drop), fill with new data, and start again, it is normal that there is a pause, right? It just happens that in pcm or native DSD mode the pause is small enough so not a big deal. While in dop there is a mode change and it will take longer if implemented using an electric switch, or worse, a audible noise if not . But if we don’t restart then there will be no pause at all.

Anyway. I think now we agree that this is how DOP works in many DACs. You don’t like this behavior and consider it’s a dac bug, and I respect that. In this case, are you willing to accept a workaround PR to address it? The PR limits it’s scope only to DOP playback and has no effect in PCM and native DSD. And the majority of the DOP supported DACs has this problem.

If you are willing to accept, I will work on it further, and I recommend Alsa do the same so people have consistent experience across the platforms. If not, I will close the PR. People can personally patch their own MPD if they need that workaround.

@MaxKellermann

This comment has been minimized.

Copy link
Member

commented Jun 12, 2019

I'd agree on adding an option which tries not stop the DAC in order to drop buffers. Those with a buggy DAC may enable it, at the cost of increased seeking latency.

@Wang-Yue

This comment has been minimized.

Copy link
Contributor Author

commented Jun 12, 2019

OK. I'll close my PR first then.

How do you want the option name be called? Or, do you mind to implement in in ALSA first, and I can support in on the CoreAudio side after that?

at the cost of increased seeking latency.

we may also let user set the buffer time. so they will have less latency at the cost of more CPU usage.

@MaxKellermann

This comment has been minimized.

Copy link
Member

commented Jun 12, 2019

Buffer time can already be configured in ALSA: https://www.musicpd.org/doc/html/plugins.html#alsa-plugin

I'm not sure how to call the new option. Naming is usually the most difficult part of any patch! Maybe avoid_restart?

@Wang-Yue

This comment has been minimized.

Copy link
Contributor Author

commented Jun 12, 2019

Buffer time can already be configured in ALSA:

I am aware of that. A year ago I proposed a patch to add something similar to Mac but was later rejected: https://github.com/MusicPlayerDaemon/MPD/pull/310/files because we later implemented start/drop/stop. Now we can get that PR in again.

Naming is usually the most difficult part of any patch! Maybe avoid_restart?

other options avoid_drop_buffer avoid_reset avoid_cancel_data avoid_cancel_buffer disable_cancel ?

Sorry I wrote ObjC every day and the best name come up to my mind is disableRestartingAndDroppingRingBufferDuringCancelAction or, better restartAndDropRingBufferDuringCancelActionEnabled if it's a property name.

@MaxKellermann

This comment has been minimized.

Copy link
Member

commented Jun 12, 2019

Your PR was not rejected. You closed it.
But this kind of change has nothing to do with this problem, because:

Note that the setting in the ALSA plugin controls ALSA's (hardware) buffer, not MPD's ring buffer

Your PR added an option to resize MPD's ring buffer, which however can be cleared without restarting the DAC.

@MaxKellermann

This comment has been minimized.

Copy link
Member

commented Jun 12, 2019

other options avoid_drop_buffer avoid_reset avoid_cancel_data avoid_cancel_buffer disable_cancel ?

avoid_drop_buffer, avoid_cancel_data and avoid_cancel_buffer are all wrong, because these are things the new option is not supposed to do. Dropping/canceling buffer/data is not what causes the pop noise, is it? The DAC restart/reset is what causes the pop noise, isn't it?

@Wang-Yue

This comment has been minimized.

Copy link
Contributor Author

commented Jun 12, 2019

Note that the setting in the ALSA plugin controls ALSA's (hardware) buffer, not MPD's ring buffer

Right. But a lot of entry level hardware(DACs) won't even have 0.5s buffer.
ALSA most probably implemented that using software (most likely ring buffer) in alsa's library (alsa-lib, not kernel buffer).

Also we don't have that kind of control in CoreAudio.
we do have kAudioDevicePropertyBufferFrameSize and kAudioSessionProperty_CurrentHardwareIOBufferDuration, but it's just a few kilobytes of data.
(I believe that's the real hardware buffer size)
The only solution we control the latency on OS X is through ring buffer.

avoid_drop_buffer, avoid_cancel_data and avoid_cancel_buffer are all wrong, because these are things the new option is not supposed to do.

That's what the documentation string of Cancel() said.

Dropping/canceling buffer/data is not what causes the pop noise, is it? The DAC restart/reset is what causes the pop noise, isn't it?

You are right canceling data is not the cause. The restart is.

However, the reason we need to restart, is because we want to cancel the data in the first place. It's an unavoidable cost canceling data needs to pay. The real technical difficulty here is we are unable to cancel data without restarting.

On Linux snd_pcm_drop will automatically trigger the stop, as is indicated on the document.
See https://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html#ga7000ca6010a1a2739daddff8e2fbb440 "Stop a PCM dropping pending frames."

On Mac, if we reset the ring buffer, we are not sure if CoreAudio consumes a complete series of samples (4 samples in DSD's case). There's no atomic way to count the size of a boost ring buffer and cancel the maximum multiples of 4 frames. Boost's ring buffer's Reset() function is neither thread-safe. So we need to stop.

@MaxKellermann

This comment has been minimized.

Copy link
Member

commented Jun 13, 2019

ALSA most probably implemented that using software (most likely ring buffer) in alsa's library (alsa-lib, not kernel buffer).

I don't think so. If this were in user space, then who would be responsible for transferring this buffer to the hardware's buffer? I don't know if this 0.5s buffer you're talking about is in the driver or really in the hardware, but I don't (need to) care. But I'm sure enough it's not in user space.

The only solution we control the latency on OS X is through ring buffer.

It doesn't affect latency if you can flush it.

avoid_drop_buffer, avoid_cancel_data and avoid_cancel_buffer are all wrong, because these are things the new option is not supposed to do.

That's what the documentation string of Cancel() said.

That's what the documentation of Cancel() said, but that's not what the new option is supposed to do, is it?
Maybe I misunderstood the option you were about to implement. You said that the DAC restart/reset causes the pop noise, so we should avoid that. That doesn't mean we need to avoid the whole Cancel() call.
So saying what Cancel() is documented to do isn't relevant here.

You are right canceling data is not the cause. The restart is.

See.

However, the reason we need to restart, is because we want to cancel the data in the first place.

On ALSA, the restart is only needed because it's the only way to clear the hardware/kernel buffer (via snd_pcm_drop()). It's not needed to clear MPD's ring buffer.

It's an unavoidable cost canceling data needs to pay. The real technical difficulty here is we are unable to cancel data without restarting.

Find a way.

On Linux snd_pcm_drop will automatically trigger the stop, as is indicated on the document.
See https://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html#ga7000ca6010a1a2739daddff8e2fbb440 "Stop a PCM dropping pending frames."

Again: this is only about the hardware/kernel buffer.

On Mac, if we reset the ring buffer, we are not sure if CoreAudio consumes a complete series of samples (4 samples in DSD's case). There's no atomic way to count the size of a boost ring buffer and cancel the maximum multiples of 4 frames. Boost's ring buffer's Reset() function is neither thread-safe. So we need to stop.

I don't understand what your problem is, and why you want to count the ring buffer size. All you need to do is make sure you always copy multiples of the "frame" size in and out of the ring buffer (with a certain definition of "frame" for DSD).

@Wang-Yue

This comment has been minimized.

Copy link
Contributor Author

commented Jun 13, 2019

I don't understand what your problem is, and why you want to count the ring buffer size. All you need to do is make sure you always copy multiples of the "frame" size in and out of the ring buffer (with a certain definition of "frame" for DSD).

We do copy multiples of the "frame" size in. but there's no guarantee the OS will consume the multiples of the "frame" size in each read. For instance, core audio may just read in a multiple of 64 bytes in a 24bit stereo PCM (6 bytes is the frame size) case, and there's nothing we can do about it.
if it doesn't consume the multiples of the "frame" size and we clear the buffer, then the stream is broken.

in addition resetting the buffer is not thread safe. So there's no guarantee from boost allow the consumer thread accessing the buffer while we dropping the ring buffer. So if we need to reset the buffer, we need to stop the audio thread.

Find a way.

We can use locks, which is wrong and will cause more hiccups in playback.

I don't see a way that we can safely drop the buffer without stopping.

@MaxKellermann

This comment has been minimized.

Copy link
Member

commented Jun 13, 2019

We do copy multiples of the "frame" size in. but there's no guarantee the OS will consume the multiples of the "frame" size in each read.

But the OS doesn't access MPD's ring buffer. It has no idea it even exists. So what do you really mean?

in addition resetting the buffer is not thread safe. So there's no guarantee from boost allow the consumer thread accessing the buffer while we dropping the ring buffer. So if we need to reset the buffer, we need to stop the audio thread.

Find a way.

We can use locks, which is wrong and will cause more hiccups in playback.

Why will that cause hiccups? An uncontended mutex which is accessed only from one thread has nearly zero overhead, not even a system call, only an atomic operation (at least on Linux - I don't know about macOS). And the atomic operation is cheap if it's accessed only by one thread (i.e. the cache line doesn't bounce between two CPUs). During normal operation, only osx_render() will access it, and only in very rare circumstances will Cancel() take it.

This isn't meant as a recommendation to use a mutex - I just think your assumption is wrong.

I don't see a way that we can safely drop the buffer without stopping.

I do. For example, with a std::atomic<> specifying the position within the ring buffer until which everything shall be discarded by osx_render().

@Wang-Yue

This comment has been minimized.

Copy link
Contributor Author

commented Jun 14, 2019

I do. For example, with a std::atomic<> specifying the position within the ring buffer until which everything shall be discarded by osx_render().

turned out to be more complicated than that. We can't clear the ring buffer in case of seeking. If we do, before Play() finishing populating new data to the buffer, there're chances that osx_render() will have nothing to read in the following call. Then the DAC panics as it don't have enough data for the next clock cycle, and it assumes that the data stream is stopped.

This cause a delay in the music. In addition, when DoP data is paused, DAC assumes that the stream stops and revert back to PCM mode. So it has the same issue as restart does.

I begin to question MPD's Cancel() design --- This is not only DoP related, but also applies to PCM. In case of seeking, the audio stream should always sync with DAC's clock, and shouldn't cause any hiccups or delays. This means sufficient data should always be present. Cancel()'s API design is against this assumption because once OS call the render function immediately after Cancel(), there's no data to read.

@MaxKellermann

This comment has been minimized.

Copy link
Member

commented Jun 15, 2019

We can't clear the ring buffer in case of seeking. If we do, before Play() finishing populating new data to the buffer, there're chances that osx_render() will have nothing to read in the following call.

Copying my reply to this from #583:
The ALSA plugin generates silence when MPD's ring buffer runs empty - which is a good solution to avoid the xrun until the seeked-to data gets available. The OSX plugin doesn't do that, and I have always assumed that CoreAudio takes care for this, but I don't know.

@MaxKellermann MaxKellermann changed the title DAC hiccup noise when seeking DSD over PCM Work around DAC bug causing pop noise when seeking DSD over PCM Jun 15, 2019

@Wang-Yue

This comment has been minimized.

Copy link
Contributor Author

commented Jun 15, 2019

The ALSA plugin generates silence when MPD's ring buffer runs empty - which is a good solution to avoid the xrun until the seeked-to data gets available. The OSX plugin doesn't do that, and I have always assumed that CoreAudio takes care for this, but I don't know.

In this case it still cause the issue of reverting to PCM. Because DOP marker is broken.

@MaxKellermann

This comment has been minimized.

Copy link
Member

commented Jun 15, 2019

If there's a bug which breaks the DoP marker, we should fix it.

@Wang-Yue

This comment has been minimized.

Copy link
Contributor Author

commented Jun 15, 2019

If there's a bug which breaks the DoP marker, we should fix it.

OS has no idea it’s playing DOP. You mentioned OS will insert silence (0x0) when buffer runs empty. So on the dac side the DOP pattern is broken.

This means we cannot drop the data.

@MaxKellermann

This comment has been minimized.

Copy link
Member

commented Jun 15, 2019

No, I did not mention "OS will insert silence" and neither did I say that "0x0" gets inserted.

Recall, this is what I wrote:

The ALSA plugin generates silence

And this is the code: https://github.com/MusicPlayerDaemon/MPD/blob/master/src/output/plugins/AlsaOutputPlugin.cxx#L1001-L1003

And "silence" isn't always 0x0. It is with PCM - but the DSD silence pattern is 0x69. But you were right when you said that sending silence breaks DoP - because the proper silence pattern is not used with DoP, because MPD's ALSA plugin asks libasound to generate the silence pattern, which libasound cannot know if MPD tunnels DSD inside PCM. That certainly is something that needs to be fixed.

@Wang-Yue

This comment has been minimized.

Copy link
Contributor Author

commented Jun 15, 2019

And this is the code:

I believe what you should do is to have an API that plugins could call (for instance in pcm_export) to generate a series of silence data given maximum number of bytes needed under the current condition (PCM, DoP, DSD). It should always cut off at multiple of frames (in DSD two frames) each call.

FillWithSilence is in ALSA, and should be moved.

if you can implement that, in osx_render, we could do

osx_render(..., UInt32 in_number_frames, ... ) {
  if (!ring_buffer.read_available()) {
    buffer_list->mBuffers[0].mDataByteSize =
      WriteSilence((uint8_t *)buffer_list->mBuffers[0].mData, in_number_frames);
  }
}

And this won't break the stream DoP pattern.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.