Audio not rendering on playback

Ask software engineering and SDK questions for developers working on Mac OS X, Windows or Linux.
  • Author
  • Message
Offline

KerryL

  • Posts: 6
  • Joined: Fri Sep 03, 2021 3:33 pm
  • Real Name: Kerry Loux

Audio not rendering on playback

PostTue Mar 04, 2025 5:30 pm

Hello,

I am attempting to render audio using the ScheduleAudioSamples() method. Roughly, playback is configured by doing (in this order):

Code: Select all
IDeckLinkOutput::SetScheduledFrameCompletionCallback()
IDeckLinkOutput::EnableVideoOutput()
IDeckLinkOutput::ScheduleVideoFrame() (three times)

IDeckLinkOutput::SetAudioCallback()
IDeckLinkOutput::EnableAudioOutput()
IDeckLinkOutput::BeginAudioPreroll()

within the RenderAudioSamples() callback:
IDeckLinkOutput::ScheduleAudioSamples() (three times, as shown below)
IDeckLinkOutput::EndAudioPreroll()


At this point, I can check the pre-rolled frame counts (note that my video frame rate is 29.97 Hz):
Code: Select all
unsigned int a, v;
deckLinkOutput->GetBufferedAudioSampleFrameCount(&a);
deckLinkOutput->GetBufferedVideoFrameCount(&v);
outStream << "Buffered frame counts are audio = " << a << " and video = " << v << std::endl;


which prints:
Code: Select all
Buffered frame counts are audio = 4803 and video = 3


Playback continues with:
Code: Select all
IDeckLinkOutput::StartScheduledPlayback()


I continue to schedule video frames in the ScheduledFrameCompleted() callback, and video playback works fine.

At the same time, I intend to schedule video frames in the RenderAudioSamples() callback. The callback fires as expected, however the buffer size I observe indicates that the audio is never pulled from the buffer. No audio is actually rendered. My RenderAudioSamples() callback is below:

Code: Select all
HRESULT STDMETHODCALLTYPE AudioOutput::RenderAudioSamples(BOOL preroll)
{
   if (!playbackRunning)
      return S_OK;

   unsigned int bufferedFrameCount;
   if (APIUtilities::CallHasError(deckLinkOutput->GetBufferedAudioSampleFrameCount(&bufferedFrameCount), _T("Failed to check audio buffer size"), outStream))
      return E_FAIL;

   outStream << "AudioOutput::RenderAudioSamples:  bufferedFrameCount = " << bufferedFrameCount << "; target = " << targetBufferedAudioCount << std::endl;
   if (bufferedFrameCount < targetBufferedAudioCount)
   {
      const unsigned int framesToAdd((targetBufferedAudioCount - bufferedFrameCount + audioSamplesPerVideoFrame - 1) / audioSamplesPerVideoFrame);
      for (unsigned int i = 0; i < framesToAdd; ++i)
      {
         VideoReader::AudioPacketData nextPacket;
         if (videoReader.GetNextAudioPacket(nextPacket))
         {
            if (!nextPacket.buffer || nextPacket.sampleCount == 0)
            {
               playbackRunning = false;
               return S_OK;
            }

            outStream << "Scheduling frame with " << nextPacket.sampleCount << " samples at " << scheduledFrameCount * audioSamplesPerVideoFrame << std::endl;
            if (APIUtilities::CallHasError(deckLinkOutput->ScheduleAudioSamples(nextPacket.buffer, nextPacket.sampleCount,
               scheduledFrameCount * audioSamplesPerVideoFrame, sampleRateHz, nullptr), _T("Failed to schedule audio samples"), outStream))
               return E_FAIL;

            if (nextPacket.buffer)
               delete[] nextPacket.buffer;

            ++scheduledFrameCount;
         }
      }
   }
   else if (preroll)
   {
      outStream << "Audio preroll complete" << std::endl;
      if (APIUtilities::CallHasError(deckLinkOutput->EndAudioPreroll(), _T("Failed to end audio preroll"), outStream))
         return E_FAIL;
      prerollComplete = true;
      prerollCompleteCondition.notify_all();
   }

   return S_OK;
}


During execution, the following output is generated:
Code: Select all
2025-03-04 11:35:31.567 : Video source frame rate = 30000 / 1001
2025-03-04 11:35:31.671 : Configuring audio output for 2 channels and 16 bits per sample
2025-03-04 11:35:31.678 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 0; target = 4803
2025-03-04 11:35:31.683 : Scheduling frame with 1601 samples at 0
2025-03-04 11:35:31.688 : Scheduling frame with 1601 samples at 1601
2025-03-04 11:35:31.692 : Scheduling frame with 1601 samples at 3202
2025-03-04 11:35:31.699 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 4803; target = 4803
2025-03-04 11:35:31.702 : Audio preroll complete
2025-03-04 11:35:31.710 : Buffered frame counts are audio = 4803 and video = 3
2025-03-04 11:35:31.716 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 4802; target = 4803
2025-03-04 11:35:31.721 : Scheduling frame with 1601 samples at 4803
2025-03-04 11:35:31.741 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 6404; target = 4803
2025-03-04 11:35:31.763 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 6404; target = 4803
2025-03-04 11:35:31.780 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 6404; target = 4803
2025-03-04 11:35:31.799 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 6404; target = 4803
2025-03-04 11:35:31.826 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 6404; target = 4803
2025-03-04 11:35:31.838 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 6404; target = 4803
2025-03-04 11:35:31.858 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 6404; target = 4803
2025-03-04 11:35:31.878 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 6404; target = 4803
2025-03-04 11:35:31.899 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 6404; target = 4803
...


Oddly, bufferedFrameCount does drop by one right after scheduled playback begins, then there are no further changes to the value bufferedFrameCount during playback. Video playback occurs as expected. I expected to see bufferedFrameCount drop as playback occurs, where we would periodically add frames to the buffer to maintain our nominal buffer size.

What steps am I missing to get audio to actually play?

Thanks,

Kerry
Offline

Cameron Nichols

Blackmagic Design

  • Posts: 465
  • Joined: Mon Sep 04, 2017 4:05 am

Re: Audio not rendering on playback

PostThu Mar 06, 2025 6:49 am

Hi Kerry,

Thanks for providing your code segments, it looks ok to me. Can I confirm 2 things:
  1. Which stream type are you providing to IDeckLinkOutput::EnableAudioOutput? Timestamped or continuous? Have you tried the other?
  2. What are the scheduled start time, timescale and playback speed parameters provided to IDeckLinkOutput::StartScheduledPlayback?
Regards
Cameron
Offline

KerryL

  • Posts: 6
  • Joined: Fri Sep 03, 2021 3:33 pm
  • Real Name: Kerry Loux

Re: Audio not rendering on playback

PostThu Mar 06, 2025 3:37 pm

Hello Cameron,

I start scheduled playback with:
Code: Select all
StartScheduledPlayback(0, 30000, 1.0);


I'm using a stream type of bmdAudioOutputStreamTimestamped.

Very interesting: I tried switching to bmdAudioOutputStreamContinuous just now, and the buffer size did drop as expected. I killed and restarted my application for a second attempt, and got exactly the same results that I did with bmdAudioOutputStreamTimestamped - the buffer size dropped by one after scheduled playback began, I added one more frame to the buffer, then the buffer size remained constant.

I'm using an UltraStudio 4k Mini - I decided to try powering the unit off and back on again. The buffer worked as expected the first time I attempted playback (and audio rendered properly), but I tried to replay the same file a second time and the buffer got "stuck" as before.

I switched back to bmdAudioOutputStreamTimestamped, powered the unit off and back on, and I observed the buffer being emptied, however it is emptied faster than new frames are read from file. No audio is actually rendered. Just as before, starting playback for a second time results in the buffer being "stuck." The output from this configuration looks like:

Code: Select all
2025-03-06 10:05:50.727 : Initializing video source for 1920 x 1080
2025-03-06 10:05:50.729 : Video source frame rate = 30000 / 1001
2025-03-06 10:05:51.133 : Configuring audio output for 2 channels and 16 bits per sample
2025-03-06 10:05:51.140 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 0; target = 4803
2025-03-06 10:05:51.145 : Scheduling frame with 1601 samples at 0
2025-03-06 10:05:51.150 : Scheduling frame with 1601 samples at 1601
2025-03-06 10:05:51.155 : Scheduling frame with 1601 samples at 3202
2025-03-06 10:05:51.163 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 4803; target = 4803
2025-03-06 10:05:51.167 : Audio preroll complete
2025-03-06 10:05:51.170 : Preroll complete!
2025-03-06 10:05:51.175 : Buffered frame counts are audio = 4803 and video = 3
2025-03-06 10:05:51.181 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 4802; target = 4803
2025-03-06 10:05:51.185 : Scheduling frame with 1601 samples at 4803
2025-03-06 10:05:51.208 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 5139; target = 4803
2025-03-06 10:05:51.228 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 4177; target = 4803
2025-03-06 10:05:51.231 : Scheduling frame with 1601 samples at 6404
2025-03-06 10:05:51.257 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 4821; target = 4803
2025-03-06 10:05:51.293 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 3856; target = 4803
2025-03-06 10:05:51.296 : Scheduling frame with 1601 samples at 8005
2025-03-06 10:05:51.308 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 3540; target = 4803
2025-03-06 10:05:51.311 : Scheduling frame with 1601 samples at 9606
2025-03-06 10:05:51.328 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 4180; target = 4803
2025-03-06 10:05:51.331 : Scheduling frame with 1601 samples at 11207
2025-03-06 10:05:51.356 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 4821; target = 4803
2025-03-06 10:05:51.367 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 3862; target = 4803
2025-03-06 10:05:51.370 : Scheduling frame with 1601 samples at 12808
2025-03-06 10:05:51.394 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 4505; target = 4803
2025-03-06 10:05:51.408 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 3533; target = 4803
2025-03-06 10:05:51.438 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 2583; target = 4803
2025-03-06 10:05:51.448 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 1623; target = 4803
2025-03-06 10:05:51.469 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 664; target = 4803
2025-03-06 10:05:51.489 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 0; target = 4803
2025-03-06 10:05:51.507 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 0; target = 4803
2025-03-06 10:05:51.528 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 0; target = 4803
2025-03-06 10:05:51.556 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 0; target = 4803
2025-03-06 10:05:51.575 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 0; target = 4803
2025-03-06 10:05:51.588 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 0; target = 4803


Frames do continue to be scheduled as they are read from file, but not fast enough to keep up with the consumption. I tried changing to 25 pre-rolled frames instead of 3 and did hear some audio rendered at the beginning of playback, but audio at the end was missing. It seems to always be that the audio stops at the half-way point of the video.

It seems that bmdAudioOutputStreamTimestamped isn't working as I expect it to, but because I'm only getting successful rendering once per startup of the UltraStudio, I wonder if I'm also doing something wrong at the end of playback?

Our application has three modes - idle (passes the signal received via SDI input through to the HDMI or SDI output for a live view), recording, and playback. So at the end of each playback session, we do the following to go back to our idle mode:

Code: Select all
IDeckLinkOutput::StopScheduledPlayback(0, NULL, 0)
< wait for ScheduledPlaybackHasStopped() callback >
IDeckLinkOutput::DisableVideoOutput()
IDeckLinkOutput::SetScheduledFrameCompletionCallback(NULL)
IDeckLinkOutput::DisableAudioOutput()
IDeckLinkOutput::SetAudioCallback(NULL)


Any other suggestions are appreciated.

Thanks,

Kerry
Offline

KerryL

  • Posts: 6
  • Joined: Fri Sep 03, 2021 3:33 pm
  • Real Name: Kerry Loux

Re: Audio not rendering on playback

PostThu Mar 06, 2025 3:52 pm

I should have clarified above - when I describe the buffer size dropping "faster than audio is read from file" - I'm throttling the read to maintain the size of the video buffer equal to the number of pre-rolled video frames. So it's not really that the read is slow - I'm observing the audio buffer being depleted faster than the video buffer.
Offline

KerryL

  • Posts: 6
  • Joined: Fri Sep 03, 2021 3:33 pm
  • Real Name: Kerry Loux

Re: Audio not rendering on playback

PostWed Mar 12, 2025 4:11 pm

I still haven't solved the issue, but I've learned a little more and I thought I would post an update in case this new information sparks any ideas.

As described in my second post above, the application has three modes, two of which are capture-based and require enabling audio and video inputs. My next troubleshooting step was to remove these features so the inputs are never enabled. When I do this, the audio doesn't get "stuck" on playback. In fact, I can enable video input only and still successfully play audio.

From the time my application starts through when playback stops, these are the DeckLink API calls:

Code: Select all
2025-03-12 11:19:41.004 : GetDeckLinkIterator()
2025-03-12 11:19:41.015 : IDeckLinkIterator::Next()
2025-03-12 11:19:41.024 : IDeckLinkInterface::Release()
2025-03-12 11:19:41.029 : Query for IDeckLinkInput
2025-03-12 11:19:41.037 : IDeckLinkInput::SetVideoInputFrameMemoryAllocator()
2025-03-12 11:19:41.040 : IDeckLinkInput::SetCallback()
2025-03-12 11:19:41.045 : IDeckLinkInput::EnableVideoInput()
<would enable audio input here>
2025-03-12 11:19:41.050 : IDeckLinkInput::StartStreams()
2025-03-12 11:19:41.054 : Query for IDeckLinkOutput

<live view active during this time; next we begin playback>

2025-03-12 11:19:51.980 : IDeckLinkInput::StopStreams()
2025-03-12 11:19:51.983 : IDeckLinkInput::DisableVideoInput()
<would disable audio input here>
2025-03-12 11:19:52.009 : IDeckLinkOutput::SetScheduledFrameCompletionCallback()
2025-03-12 11:19:52.012 : IDeckLinkOutput::EnableVideoOutput()
2025-03-12 11:19:52.019 : IDeckLinkOutput::ScheduleVideoFrame(videoFrame, 0, 1001, 30000)
2025-03-12 11:19:52.025 : IDeckLinkOutput::ScheduleVideoFrame(videoFrame, 1001, 1001, 30000)
2025-03-12 11:19:52.031 : IDeckLinkOutput::ScheduleVideoFrame(videoFrame, 2002, 1001, 30000)
2025-03-12 11:19:52.041 : IDeckLinkOutput::SetAudioCallback()
2025-03-12 11:19:52.045 : IDeckLinkOutput::EnableAudioOutput(48000, 16-bit integer, 2, timestamped)
2025-03-12 11:19:52.049 : IDeckLinkOutput::BeginAudioPreroll()
2025-03-12 11:19:52.056 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 0; target = 4803
2025-03-12 11:19:52.062 : IDeckLinkOutput::ScheduleAudioSamples(buffer, 800, 0, 48000, null)
2025-03-12 11:19:52.067 : IDeckLinkOutput::ScheduleAudioSamples(buffer, 800, 1601, 48000, null)
2025-03-12 11:19:52.082 : IDeckLinkOutput::ScheduleAudioSamples(buffer, 800, 3202, 48000, null)
2025-03-12 11:19:52.086 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 4002; target = 4803
2025-03-12 11:19:52.090 : IDeckLinkOutput::ScheduleAudioSamples(buffer, 800, 4803, 48000, null)
2025-03-12 11:19:52.094 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 5603; target = 4803
2025-03-12 11:19:52.095 : IDeckLinkOutput::EndAudioPreroll()
2025-03-12 11:19:52.101 : IDeckLinkOutput::StartScheduledPlayback(0, 30000, 1.0)
2025-03-12 11:19:52.103 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 5602; target = 4803
2025-03-12 11:19:52.112 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 5602; target = 4803
2025-03-12 11:19:52.133 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 4963; target = 4803
2025-03-12 11:19:52.137 : IDeckLinkOutput::ScheduleVideoFrame(videoFrame, 3003, 1001, 30000)
2025-03-12 11:19:52.151 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 3999; target = 4803

<playback continues>

2025-03-12 11:19:56.033 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 5078; target = 4803
2025-03-12 11:19:56.043 : IDeckLinkOutput::ScheduleVideoFrame(videoFrame, 120120, 1001, 30000)
2025-03-12 11:19:56.053 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 4113; target = 4803
2025-03-12 11:19:56.063 : IDeckLinkOutput::ScheduleAudioSamples(buffer, 800, 193721, 48000, null)
2025-03-12 11:19:56.069 : IDeckLinkOutput::StopScheduledPlayback(0, NULL, 0)
2025-03-12 11:19:56.074 : AudioOutput::RenderAudioSamples:  bufferedFrameCount = 4761; target = 4803
2025-03-12 11:19:56.079 : IDeckLinkOutput::ScheduleAudioSamples(buffer, 800, 195322, 48000, null)
2025-03-12 11:19:56.089 : IDeckLinkOutput::DisableVideoOutput()
2025-03-12 11:19:56.094 : IDeckLinkOutput::SetScheduledFrameCompletionCallback(null)
2025-03-12 11:19:56.098 : IDeckLinkOutput::DisableAudioOutput()
2025-03-12 11:19:56.102 : IDeckLinkOutput::SetAudioCallback(null)
2025-03-12 11:19:56.110 : IDeckLinkInput::SetVideoInputFrameMemoryAllocator()
2025-03-12 11:19:56.113 : IDeckLinkInput::SetCallback()
2025-03-12 11:19:56.118 : IDeckLinkInput::EnableVideoInput()
<would re-enable audio input here>
2025-03-12 11:19:56.123 : IDeckLinkInput::StartStreams()


If at the point marked <would enable audio input here> I call IDeckLinkInput::EnableAudioInput() and at the point marked <would disable audio input here> I call IDeckLinkInput::DisableAudioInput, then the buffer count become stuck on playback as described in my earlier posts.

I don't see any notes in the documentation about switching between capture and playback modes. Any thoughts on how to resolve this would be greatly appreciated.

Thanks,

Kerry

Return to Software Developers

Who is online

Users browsing this forum: No registered users and 5 guests