// Copyright 2019 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 "garnet/drivers/audio/virtual_audio/virtual_audio_control_impl.h"

#include <ddk/debug.h>
#include <lib/async/cpp/task.h>

#include "garnet/drivers/audio/virtual_audio/virtual_audio_device_impl.h"
#include "garnet/drivers/audio/virtual_audio/virtual_audio_stream.h"

namespace virtual_audio {

// static
//
// Unbind any published children (which will remove them), shut down any async
// loop, ensure nothing is in flight, then remove ourselves from the dev tree.
//
// Unbind proceeds "down" from parent to child, while Release proceeds "up"
// (called for parent once all children have been released).
void VirtualAudioControlImpl::DdkUnbind(void* ctx) {
  ZX_DEBUG_ASSERT(ctx != nullptr);

  auto self = static_cast<VirtualAudioControlImpl*>(ctx);

  // Close any remaining control (or stream) bindings, freeing those drivers.
  self->ReleaseBindings();

  // Now remove the control device itself (this later calls our DdkRelease).
  device_remove(self->dev_node());
}

// static
//
// Always called after DdkUnbind, which should guarantee that lists are emptied.
// Any last cleanup or logical consistency checks would be done here. By the
// time this is called, all child devices have already been released.
void VirtualAudioControlImpl::DdkRelease(void* ctx) {
  ZX_DEBUG_ASSERT(ctx != nullptr);

  // DevMgr has returned ownership of whatever we provided as driver ctx (our
  // VirtualAudioControlImpl). When this functions returns, this unique_ptr will
  // go out of scope, triggering ~VirtualAudioControlImpl.
  std::unique_ptr<VirtualAudioControlImpl> control_ptr(
      static_cast<VirtualAudioControlImpl*>(ctx));

  // By now, all our lists should be empty.
  ZX_DEBUG_ASSERT(control_ptr->bindings_.size() == 0);
  ZX_DEBUG_ASSERT(control_ptr->input_bindings_.size() == 0);
  ZX_DEBUG_ASSERT(control_ptr->output_bindings_.size() == 0);
}

// static
//
zx_status_t VirtualAudioControlImpl::DdkMessage(void* ctx, fidl_msg_t* msg,
                                                fidl_txn_t* txn) {
  ZX_DEBUG_ASSERT(ctx != nullptr);

  return fuchsia_virtualaudio_Forwarder_dispatch(ctx, txn, msg, &fidl_ops_);
}

// static
//
fuchsia_virtualaudio_Forwarder_ops_t VirtualAudioControlImpl::fidl_ops_ = {
    .SendControl =
        [](void* ctx, zx_handle_t control_request) {
          ZX_DEBUG_ASSERT(ctx != nullptr);
          return static_cast<VirtualAudioControlImpl*>(ctx)->SendControl(
              zx::channel(control_request));
        },
    .SendInput =
        [](void* ctx, zx_handle_t input_request) {
          ZX_DEBUG_ASSERT(ctx != nullptr);
          return static_cast<VirtualAudioControlImpl*>(ctx)->SendInput(
              zx::channel(input_request));
        },
    .SendOutput =
        [](void* ctx, zx_handle_t output_request) {
          ZX_DEBUG_ASSERT(ctx != nullptr);
          return static_cast<VirtualAudioControlImpl*>(ctx)->SendOutput(
              zx::channel(output_request));
        },
};

// A client connected to fuchsia.virtualaudio.Control hosted by the virtual
// audio service, which is forwarding the server-side binding to us.
zx_status_t VirtualAudioControlImpl::SendControl(
    zx::channel control_request_channel) {
  if (!control_request_channel.is_valid()) {
    zxlogf(TRACE, "%s: channel from request handle is invalid\n", __func__);
    return ZX_ERR_INVALID_ARGS;
  }

  // VirtualAudioControlImpl is a singleton so just save the binding in a list.
  // Note, using the default dispatcher means that we will be running on the
  // same that drives all of our peer devices in the /dev/test device host.
  // We should ensure there are no long VirtualAudioControl operations.
  bindings_.AddBinding(this,
                       fidl::InterfaceRequest<fuchsia::virtualaudio::Control>(
                           std::move(control_request_channel)));
  return ZX_OK;
}

// A client connected to fuchsia.virtualaudio.Input hosted by the
// virtual audio service, which is forwarding the server-side binding to us.
zx_status_t VirtualAudioControlImpl::SendInput(
    zx::channel input_request_channel) {
  if (!input_request_channel.is_valid()) {
    zxlogf(TRACE, "%s: channel from request handle is invalid\n", __func__);
    return ZX_ERR_INVALID_ARGS;
  }

  // Create an VirtualAudioDeviceImpl for this binding; save it in our list.
  // Note, using the default dispatcher means that we will be running on the
  // same that drives all of our peer devices in the /dev/test device host.
  // We should be mindful of this if doing long VirtualAudioInput operations.
  input_bindings_.AddBinding(
      VirtualAudioDeviceImpl::Create(this, true),
      fidl::InterfaceRequest<fuchsia::virtualaudio::Input>(
          std::move(input_request_channel)));

  auto* binding = input_bindings_.bindings().back().get();
  binding->impl()->SetBinding(binding);

  return ZX_OK;
}

zx_status_t VirtualAudioControlImpl::SendOutput(
    zx::channel output_request_channel) {
  if (!output_request_channel.is_valid()) {
    zxlogf(TRACE, "%s: channel from request handle is invalid\n", __func__);
    return ZX_ERR_INVALID_ARGS;
  }

  // Create a VirtualAudioDeviceImpl for this binding; save it in our list.
  // Note, using the default dispatcher means that we will be running on the
  // same that drives all of our peer devices in the /dev/test device host.
  // We should be mindful of this if doing long VirtualAudioOutput operations.
  output_bindings_.AddBinding(
      VirtualAudioDeviceImpl::Create(this, false),
      fidl::InterfaceRequest<fuchsia::virtualaudio::Output>(
          std::move(output_request_channel)));

  auto* binding = output_bindings_.bindings().back().get();
  binding->impl()->SetBinding(binding);

  return ZX_OK;
}

// Reset any remaining bindings of Controls, Inputs and Outputs.
// This is called during Unbind, at which time child drivers should be gone (and
// input_bindings_ and output_bindings_ empty).
void VirtualAudioControlImpl::ReleaseBindings() {
  bindings_.CloseAll();
  input_bindings_.CloseAll();
  output_bindings_.CloseAll();

  zxlogf(TRACE,
         "%s for %p: now we have %lu/%lu/%lu control/input/output bindings\n",
         __func__, this, bindings_.size(), input_bindings_.size(),
         output_bindings_.size());
}

void VirtualAudioControlImpl::PostToDispatcher(
    fit::closure task_to_post) const {
  async::PostTask(dispatcher(), std::move(task_to_post));
}

// Allow subsequent new stream creation -- but do not automatically reactivate
// any streams that may have been deactivated (removed) by the previous Disable.
// Upon construction, the default state of this object is Enabled. The (empty)
// callback is used to synchronize with other in-flight asynchronous operations.
void VirtualAudioControlImpl::Enable(EnableCallback enable_callback) {
  enabled_ = true;

  enable_callback();
}

// Deactivate active streams and prevent subsequent new stream creation. Audio
// devices vanish from the dev tree (VirtualAudioStream objects are freed), but
// Input and Output channels remain open and can be reconfigured. Once Enable is
// called; they can be re-added without losing configuration state. The (empty)
// callback is used to synchronize with other in-flight asynchronous operations.
void VirtualAudioControlImpl::Disable(DisableCallback disable_callback) {
  if (enabled_) {
    for (auto& binding : input_bindings_.bindings()) {
      binding->impl()->RemoveStream();
    }
    for (auto& binding : output_bindings_.bindings()) {
      binding->impl()->RemoveStream();
    }

    enabled_ = false;
  }

  disable_callback();
}

}  // namespace virtual_audio
