void
nsBrowserElement::InitBrowserElementAPI()
{
  RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
  NS_ENSURE_TRUE_VOID(frameLoader);

  if (!frameLoader->OwnerIsMozBrowserFrame()) {
    return;
  }

  if (!mBrowserElementAPI) {
    mBrowserElementAPI = do_CreateInstance("@mozilla.org/dom/browser-element-api;1");
    if (NS_WARN_IF(!mBrowserElementAPI)) {
      return;
    }
  }
  mBrowserElementAPI->SetFrameLoader(frameLoader);
}
void
nsBrowserElement::InitBrowserElementAPI()
{
  bool isMozBrowserOrApp;
  nsCOMPtr<nsIFrameLoader> frameLoader = GetFrameLoader();
  NS_ENSURE_TRUE_VOID(frameLoader);
  nsresult rv = frameLoader->GetOwnerIsMozBrowserOrAppFrame(&isMozBrowserOrApp);
  NS_ENSURE_SUCCESS_VOID(rv);
  rv = frameLoader->GetOwnerIsWidget(&mOwnerIsWidget);
  NS_ENSURE_SUCCESS_VOID(rv);

  if (!isMozBrowserOrApp) {
    return;
  }

  if (!mBrowserElementAPI) {
    mBrowserElementAPI = do_CreateInstance("@mozilla.org/dom/browser-element-api;1");
    if (NS_WARN_IF(!mBrowserElementAPI)) {
      return;
    }
  }
  mBrowserElementAPI->SetFrameLoader(frameLoader);
}
void
nsBrowserElement::GetAllowedAudioChannels(
                 nsTArray<RefPtr<BrowserElementAudioChannel>>& aAudioChannels,
                 ErrorResult& aRv)
{
  aAudioChannels.Clear();

  // If empty, it means that this is the first call of this method.
  if (mBrowserElementAudioChannels.IsEmpty()) {
    nsCOMPtr<nsIFrameLoader> frameLoader = GetFrameLoader();
    if (NS_WARN_IF(!frameLoader)) {
      return;
    }

    bool isMozBrowserOrApp;
    aRv = frameLoader->GetOwnerIsMozBrowserOrAppFrame(&isMozBrowserOrApp);
    if (NS_WARN_IF(aRv.Failed())) {
      return;
    }

    if (!isMozBrowserOrApp) {
      return;
    }

    nsCOMPtr<nsIDOMElement> frameElement;
    aRv = frameLoader->GetOwnerElement(getter_AddRefs(frameElement));
    if (NS_WARN_IF(aRv.Failed())) {
      return;
    }

    MOZ_ASSERT(frameElement);

    nsCOMPtr<nsIDOMDocument> doc;
    aRv = frameElement->GetOwnerDocument(getter_AddRefs(doc));
    if (NS_WARN_IF(aRv.Failed())) {
      return;
    }

    MOZ_ASSERT(doc);

    nsCOMPtr<mozIDOMWindowProxy> win;
    aRv = doc->GetDefaultView(getter_AddRefs(win));
    if (NS_WARN_IF(aRv.Failed())) {
      return;
    }

    MOZ_ASSERT(win);

    auto* window = nsPIDOMWindowOuter::From(win);
    nsPIDOMWindowInner* innerWindow = window->GetCurrentInnerWindow();

    nsCOMPtr<nsIMozBrowserFrame> mozBrowserFrame =
      do_QueryInterface(frameElement);
    if (NS_WARN_IF(!mozBrowserFrame)) {
      aRv.Throw(NS_ERROR_FAILURE);
      return;
    }

    nsAutoString manifestURL;
    aRv = mozBrowserFrame->GetAppManifestURL(manifestURL);
    if (NS_WARN_IF(aRv.Failed())) {
      return;
    }

    nsCOMPtr<mozIApplication> parentApp;
    aRv = GetParentApplication(getter_AddRefs(parentApp));
    if (NS_WARN_IF(aRv.Failed())) {
      return;
    }

    MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
            ("nsBrowserElement, GetAllowedAudioChannels, this = %p\n", this));

    GenerateAllowedAudioChannels(innerWindow, frameLoader, mBrowserElementAPI,
                                 manifestURL, parentApp,
                                 mBrowserElementAudioChannels, aRv);
    if (NS_WARN_IF(aRv.Failed())) {
      return;
    }
  }

  aAudioChannels.AppendElements(mBrowserElementAudioChannels);
}
void
nsBrowserElement::GetAllowedAudioChannels(
                 nsTArray<nsRefPtr<BrowserElementAudioChannel>>& aAudioChannels,
                 ErrorResult& aRv)
{
  aAudioChannels.Clear();

  // If empty, it means that this is the first call of this method.
  if (mBrowserElementAudioChannels.IsEmpty()) {
    nsCOMPtr<nsIFrameLoader> frameLoader = GetFrameLoader();
    if (NS_WARN_IF(!frameLoader)) {
      return;
    }

    bool isBrowserOrApp;
    aRv = frameLoader->GetOwnerIsBrowserOrAppFrame(&isBrowserOrApp);
    if (NS_WARN_IF(aRv.Failed())) {
      return;
    }

    if (!isBrowserOrApp) {
      return;
    }

    nsCOMPtr<nsIDOMElement> frameElement;
    aRv = frameLoader->GetOwnerElement(getter_AddRefs(frameElement));
    if (NS_WARN_IF(aRv.Failed())) {
      return;
    }

    MOZ_ASSERT(frameElement);

    nsCOMPtr<nsIDOMDocument> doc;
    aRv = frameElement->GetOwnerDocument(getter_AddRefs(doc));
    if (NS_WARN_IF(aRv.Failed())) {
      return;
    }

    MOZ_ASSERT(doc);

    nsCOMPtr<nsIDOMWindow> win;
    aRv = doc->GetDefaultView(getter_AddRefs(win));
    if (NS_WARN_IF(aRv.Failed())) {
      return;
    }

    MOZ_ASSERT(win);

    nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(win);

    if (!window->IsInnerWindow()) {
      window = window->GetCurrentInnerWindow();
    }

    nsCOMPtr<nsIMozBrowserFrame> mozBrowserFrame =
      do_QueryInterface(frameElement);
    if (NS_WARN_IF(!mozBrowserFrame)) {
      aRv.Throw(NS_ERROR_FAILURE);
      return;
    }

    nsAutoString manifestURL;
    aRv = mozBrowserFrame->GetAppManifestURL(manifestURL);
    if (NS_WARN_IF(aRv.Failed())) {
      return;
    }

    GenerateAllowedAudioChannels(window, frameLoader, mBrowserElementAPI,
                                 manifestURL, mBrowserElementAudioChannels,
                                 aRv);
    if (NS_WARN_IF(aRv.Failed())) {
      return;
    }
  }

  aAudioChannels.AppendElements(mBrowserElementAudioChannels);
}