src/media/audio/audio_core/audio_output_unittest.cc
// Verify we call StartMixJob multiple times if FinishMixJob does not fill buffer.
Verify we call StartMixJob multiple times if FinishMixJob does not fill buffer.
Verify we call StartMixJob multiple times if FinishMixJob does not fill buffer .
TEST_F(AudioOutputTest, ProcessMultipleMixJobs) {
  const Format format =
      Format::Create({
                         .sample_format = fuchsia::media::AudioSampleFormat::FLOAT,
                         .channels = 2,
                         .frames_per_second = 48000,
                     })
          .take_value();
  auto pipeline_owned = std::make_unique<TestOutputPipeline>(format);
  auto pipeline = pipeline_owned.get();
  audio_output_->set_output_pipeline(std::move(pipeline_owned));
  static const TimelineFunction kOneFramePerMs = TimelineFunction(TimelineRate(1, 1'000'000));
  audio_output_->SetupMixTask(DeviceConfig::OutputDeviceProfile(), zx::msec(1).to_msecs(),
                              kOneFramePerMs);
  const uint32_t kBufferFrames = 25;
  const uint32_t kBufferSamples = kBufferFrames * 2;
  const uint32_t kNumBuffers = 4;
  std::vector<float> buffer(kBufferSamples);
  for (size_t sample = 0; sample < kBufferSamples; ++sample) {
    buffer[sample] = static_cast<float>(sample);
  }
  for (size_t i = 0; i < kNumBuffers; ++i) {
    pipeline->Enqueue(ReadableStream::Buffer(i * kBufferFrames, kBufferFrames, buffer.data(), true,
                                             StreamUsageMask(), Gain::kUnityGainDb));
  }
  uint32_t mix_jobs = 0;
  uint32_t frames_finished = 0;
  audio_output_->set_start_mix_delegate([&frames_finished, &mix_jobs](zx::time now) {
    ++mix_jobs;
    return TestAudioOutput::FrameSpan{
        .start = frames_finished,
        .length = (kBufferFrames * kNumBuffers) - frames_finished,
        .is_mute = false,
    };
  });
  audio_output_->set_finish_mix_delegate([&frames_finished](auto span, auto buffer) {
    EXPECT_EQ(span.start, frames_finished);
    EXPECT_FALSE(span.is_mute);
    EXPECT_NE(buffer, nullptr);
    for (size_t sample = 0; sample < kBufferSamples; ++sample) {
      EXPECT_FLOAT_EQ(static_cast<float>(sample), buffer[sample]);
    }
    frames_finished += span.length;
  });
  audio_output_->Process();
  EXPECT_EQ(frames_finished, kNumBuffers * kBufferFrames);
  EXPECT_EQ(mix_jobs, kNumBuffers);
}
TEST_F ( AudioOutputTest , ProcessMultipleMixJobs ) { const Format format = Format :: Create ( { . sample_format = fuchsia :: media :: AudioSampleFormat :: FLOAT , . channels = 2 , . frames_per_second = 48000 , } ) . take_value ( ) ; auto pipeline_owned = std :: make_unique < TestOutputPipeline > ( format ) ; auto pipeline = pipeline_owned . get ( ) ; audio_output_ -> set_output_pipeline ( std :: move ( pipeline_owned ) ) ; static const TimelineFunction kOneFramePerMs = TimelineFunction ( TimelineRate ( 1 , 1'000'000 ) ) ; audio_output_ -> SetupMixTask ( DeviceConfig :: OutputDeviceProfile ( ) , zx :: msec ( 1 ) . to_msecs ( ) , kOneFramePerMs ) ; const uint32_t kBufferFrames = 25 ; const uint32_t kBufferSamples = kBufferFrames * 2 ; const uint32_t kNumBuffers = 4 ; std :: vector < float > buffer ( kBufferSamples ) ; for ( size_t sample = 0 ; sample < kBufferSamples ; ++ sample ) { buffer [ sample ] = static_cast < float > ( sample ) ; } for ( size_t i = 0 ; i < kNumBuffers ; ++ i ) { pipeline -> Enqueue ( ReadableStream :: Buffer ( i * kBufferFrames , kBufferFrames , buffer . data ( ) , true , StreamUsageMask ( ) , Gain :: kUnityGainDb ) ) ; } uint32_t mix_jobs = 0 ; uint32_t frames_finished = 0 ; audio_output_ -> set_start_mix_delegate ( [ & frames_finished , & mix_jobs ] ( zx :: time now ) { ++ mix_jobs ; return TestAudioOutput :: FrameSpan { . start = frames_finished , . length = ( kBufferFrames * kNumBuffers ) - frames_finished , . is_mute = false , } ; } ) ; audio_output_ -> set_finish_mix_delegate ( [ & frames_finished ] ( auto span , auto buffer ) { EXPECT_EQ ( span . start , frames_finished ) ; EXPECT_FALSE ( span . is_mute ) ; EXPECT_NE ( buffer , nullptr ) ; for ( size_t sample = 0 ; sample < kBufferSamples ; ++ sample ) { EXPECT_FLOAT_EQ ( static_cast < float > ( sample ) , buffer [ sample ] ) ; } frames_finished += span . length ; } ) ; audio_output_ -> Process ( ) ; EXPECT_EQ ( frames_finished , kNumBuffers * kBufferFrames ) ; EXPECT_EQ ( mix_jobs , kNumBuffers ) ; }
Verify we call StartMixJob multiple times if FinishMixJob does not fill buffer.
Verify we call StartMixJob multiple times if FinishMixJob does not fill buffer .
// Use an output pipeline that will always return nullopt from ReadLock. // Setup our buffer with data that is just the value of frame 'N' is 'N'. // Enqueue several buffers, each with the same payload buffer. // Return some valid, non-silent frame range from StartMixJob. // Now do a mix.