text: // Copyright 2016 The Fuchsia Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #include "src/media/audio/audio_core/audio_core_impl.h"
  
  #include <lib/async/cpp/task.h>
  
  #include "src/media/audio/audio_core/audio_admin.h"
  #include "src/media/audio/audio_core/audio_capturer.h"
  #include "src/media/audio/audio_core/audio_device_manager.h"
  #include "src/media/audio/audio_core/audio_renderer.h"
  #include "src/media/audio/audio_core/process_config.h"
  #include "src/media/audio/audio_core/stream_usage.h"
  #include "src/media/audio/audio_core/throttle_output.h"
  #include "src/media/audio/lib/format/format.h"
  #include "src/media/audio/lib/logging/logging.h"
  
  namespace media::audio {
  
  AudioCoreImpl::AudioCoreImpl(Context* context) : context_(*context) {
    FX_DCHECK(context);
    // The main async_t here is responsible for receiving audio payloads sent by applications, so it
    // has real time requirements just like mixing threads. Ideally, this task would not run on the
    // same thread that processes *all* non-mix audio service jobs (even non-realtime ones), but that
    // will take more significant restructuring, when we can deal with realtime requirements in place.
    AcquireAudioCoreImplProfile(&context_.component_context(),
                                [](zx_status_t status, zx::profile profile) {
                                  FX_DCHECK(profile);
                                  FX_DCHECK(status == ZX_OK);
                                  if (status == ZX_OK && profile) {
                                    status = zx::thread::self()->set_profile(profile, 0);
                                    FX_DCHECK(status == ZX_OK);
                                  }
                                });
  
    // Set up our audio policy.
    LoadDefaults();
  
    context_.component_context().outgoing()->AddPublicService(bindings_.GetHandler(this));
  }
  
  AudioCoreImpl::~AudioCoreImpl() { Shutdown(); }
  
  void AudioCoreImpl::Shutdown() {
    TRACE_DURATION("audio", "AudioCoreImpl::Shutdown");
    context_.device_manager().Shutdown();
  }
  
  void AudioCoreImpl::CreateAudioRenderer(
      fidl::InterfaceRequest<fuchsia::media::AudioRenderer> audio_renderer_request) {
    TRACE_DURATION("audio", "AudioCoreImpl::CreateAudioRenderer");
    AUDIO_LOG(DEBUG);
  
    context_.route_graph().AddRenderer(
        AudioRenderer::Create(std::move(audio_renderer_request), &context_));
  }
  
  void AudioCoreImpl::CreateAudioCapturerWithConfiguration(
      fuchsia::media::AudioStreamType stream_type,
      fuchsia::media::AudioCapturerConfiguration configuration,
      fidl::InterfaceRequest<fuchsia::media::AudioCapturer> audio_capturer_request) {
    auto format = Format::Create(stream_type);
    if (format.is_error()) {
      FX_LOGS(WARNING) << "Attempted to create AudioCapturer with invalid stream type";
      return;
    }
    context_.route_graph().AddCapturer(AudioCapturer::Create(
        std::move(configuration), std::make_optional<Format>(format.take_value()),
        std::move(audio_capturer_request), &context_));
  }
  
  void AudioCoreImpl::CreateAudioCapturer(
      bool loopback, fidl::InterfaceRequest<fuchsia::media::AudioCapturer> audio_capturer_request) {
    TRACE_DURATION("audio", "AudioCoreImpl::CreateAudioCapturer");
    AUDIO_LOG(DEBUG);
  
    auto configuration = loopback ? fuchsia::media::AudioCapturerConfiguration::WithLoopback(
                                        fuchsia::media::LoopbackAudioCapturerConfiguration())
                                  : fuchsia::media::AudioCapturerConfiguration::WithInput(
                                        fuchsia::media::InputAudioCapturerConfiguration());
    context_.route_graph().AddCapturer(
        AudioCapturer::Create(std::move(configuration), /*format= */ std::nullopt,
                              std::move(audio_capturer_request), &context_));
  }
  
  void AudioCoreImpl::SetRenderUsageGain(fuchsia::media::AudioRenderUsage render_usage,
                                         float gain_db) {
    TRACE_DURATION("audio", "AudioCoreImpl::SetRenderUsageGain");
    context_.volume_manager().SetUsageGain(
        fuchsia::media::Usage::WithRenderUsage(std::move(render_usage)), gain_db);
  }
  
  void AudioCoreImpl::SetCaptureUsageGain(fuchsia::media::AudioCaptureUsage capture_usage,
                                          float gain_db) {
    TRACE_DURATION("audio", "AudioCoreImpl::SetCaptureUsageGain");
    context_.volume_manager().SetUsageGain(
        fuchsia::media::Usage::WithCaptureUsage(std::move(capture_usage)), gain_db);
  }
  
  void AudioCoreImpl::BindUsageVolumeControl(
      fuchsia::media::Usage usage,
      fidl::InterfaceRequest<fuchsia::media::audio::VolumeControl> volume_control) {
    TRACE_DURATION("audio", "AudioCoreImpl::BindUsageVolumeControl");
    if (usage.is_render_usage()) {
      context_.volume_manager().BindUsageVolumeClient(std::move(usage), std::move(volume_control));
    } else {
      volume_control.Close(ZX_ERR_NOT_SUPPORTED);
    }
  }
  
  void AudioCoreImpl::SetInteraction(fuchsia::media::Usage active, fuchsia::media::Usage affected,
                                     fuchsia::media::Behavior behavior) {
    TRACE_DURATION("audio", "AudioCoreImpl::SetInteraction");
    context_.audio_admin().SetInteraction(std::move(active), std::move(affected), behavior);
  }
  
  void AudioCoreImpl::LoadDefaults() {
    TRACE_DURATION("audio", "AudioCoreImpl::LoadDefaults");
    auto policy = PolicyLoader::LoadPolicy();
    context_.audio_admin().SetInteractionsFromAudioPolicy(std::move(policy));
  }
  
  void AudioCoreImpl::ResetInteractions() {
    TRACE_DURATION("audio", "AudioCoreImpl::ResetInteractions");
    context_.audio_admin().ResetInteractions();
  }
  
  }  // namespace media::audio
  