already_AddRefed<MediaDataDecoder>
EMEDecoderModule::CreateAudioDecoder(const CreateDecoderParams& aParams)
{
  MOZ_ASSERT(aParams.mConfig.mCrypto.mValid);

  if (SupportsMimeType(aParams.mConfig.mMimeType, nullptr)) {
    // GMP decodes. Assume that means it can decrypt too.
    RefPtr<MediaDataDecoderProxy> wrapper =
      CreateDecoderWrapper(aParams.mCallback, mProxy, aParams.mTaskQueue);
    auto gmpParams = GMPAudioDecoderParams(aParams).WithCallback(wrapper);
    wrapper->SetProxyTarget(new EMEAudioDecoder(mProxy, gmpParams));
    return wrapper.forget();
  }

  MOZ_ASSERT(mPDM);
  RefPtr<MediaDataDecoder> decoder(mPDM->CreateDecoder(aParams));
  if (!decoder) {
    return nullptr;
  }

  RefPtr<MediaDataDecoder> emeDecoder(new EMEDecryptor(decoder,
                                                       aParams.mCallback,
                                                       mProxy,
                                                       AbstractThread::GetCurrent()->AsTaskQueue()));
  return emeDecoder.forget();
}
already_AddRefed<MediaDataDecoder>
EMEDecoderModule::CreateAudioDecoder(const AudioInfo& aConfig,
                                     FlushableTaskQueue* aAudioTaskQueue,
                                     MediaDataDecoderCallback* aCallback)
{
  MOZ_ASSERT(aConfig.mCrypto.mValid);

  if (mCDMDecodesAudio) {
    RefPtr<MediaDataDecoderProxy> wrapper = CreateDecoderWrapper(aCallback, mProxy, aAudioTaskQueue);
    wrapper->SetProxyTarget(new EMEAudioDecoder(mProxy,
                                                aConfig,
                                                aAudioTaskQueue,
                                                wrapper->Callback()));
    return wrapper.forget();
  }

  MOZ_ASSERT(mPDM);
  RefPtr<MediaDataDecoder> decoder(
    mPDM->CreateDecoder(aConfig, aAudioTaskQueue, aCallback));
  if (!decoder) {
    return nullptr;
  }

  RefPtr<MediaDataDecoder> emeDecoder(new EMEDecryptor(decoder,
                                                         aCallback,
                                                         mProxy,
                                                         AbstractThread::GetCurrent()->AsTaskQueue()));
  return emeDecoder.forget();
}
already_AddRefed<MediaDataDecoder>
GMPDecoderModule::CreateAudioDecoder(const AudioInfo& aConfig,
                                     FlushableTaskQueue* aAudioTaskQueue,
                                     MediaDataDecoderCallback* aCallback)
{
  if (!aConfig.mMimeType.EqualsLiteral("audio/mp4a-latm")) {
    return nullptr;
  }

  RefPtr<MediaDataDecoderProxy> wrapper = CreateDecoderWrapper(aCallback);
  wrapper->SetProxyTarget(new GMPAudioDecoder(aConfig,
                                              aAudioTaskQueue,
                                              wrapper->Callback()));
  return wrapper.forget();
}
already_AddRefed<MediaDataDecoder>
GMPDecoderModule::CreateAudioDecoder(const CreateDecoderParams& aParams)
{
  if (!aParams.mConfig.mMimeType.EqualsLiteral("audio/mp4a-latm")) {
    return nullptr;
  }

  if (aParams.mDiagnostics) {
    const Maybe<nsCString> preferredGMP = PreferredGMP(aParams.mConfig.mMimeType);
    if (preferredGMP.isSome()) {
      aParams.mDiagnostics->SetGMP(preferredGMP.value());
    }
  }

  RefPtr<MediaDataDecoderProxy> wrapper = CreateDecoderWrapper(aParams.mCallback);
  auto params = GMPAudioDecoderParams(aParams).WithCallback(wrapper);
  wrapper->SetProxyTarget(new GMPAudioDecoder(params));
  return wrapper.forget();
}
already_AddRefed<MediaDataDecoder>
GMPDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig,
                                     layers::LayersBackend aLayersBackend,
                                     layers::ImageContainer* aImageContainer,
                                     FlushableTaskQueue* aVideoTaskQueue,
                                     MediaDataDecoderCallback* aCallback)
{
  if (!aConfig.mMimeType.EqualsLiteral("video/avc")) {
    return nullptr;
  }

  RefPtr<MediaDataDecoderProxy> wrapper = CreateDecoderWrapper(aCallback);
  wrapper->SetProxyTarget(new GMPVideoDecoder(aConfig,
                                              aLayersBackend,
                                              aImageContainer,
                                              aVideoTaskQueue,
                                              wrapper->Callback()));
  return wrapper.forget();
}
already_AddRefed<MediaDataDecoder>
GMPDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams)
{
  if (!MP4Decoder::IsH264(aParams.mConfig.mMimeType) &&
      !VPXDecoder::IsVP8(aParams.mConfig.mMimeType) &&
      !VPXDecoder::IsVP9(aParams.mConfig.mMimeType)) {
    return nullptr;
  }

  if (aParams.mDiagnostics) {
    const Maybe<nsCString> preferredGMP = PreferredGMP(aParams.mConfig.mMimeType);
    if (preferredGMP.isSome()) {
      aParams.mDiagnostics->SetGMP(preferredGMP.value());
    }
  }

  RefPtr<MediaDataDecoderProxy> wrapper = CreateDecoderWrapper(aParams.mCallback);
  auto params = GMPVideoDecoderParams(aParams).WithCallback(wrapper);
  wrapper->SetProxyTarget(new GMPVideoDecoder(params));
  return wrapper.forget();
}
already_AddRefed<MediaDataDecoder>
EMEDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig,
                                     layers::LayersBackend aLayersBackend,
                                     layers::ImageContainer* aImageContainer,
                                     FlushableTaskQueue* aVideoTaskQueue,
                                     MediaDataDecoderCallback* aCallback)
{
  MOZ_ASSERT(aConfig.mCrypto.mValid);

  if (mCDMDecodesVideo) {
    RefPtr<MediaDataDecoderProxy> wrapper = CreateDecoderWrapper(aCallback, mProxy, aVideoTaskQueue);
    wrapper->SetProxyTarget(new EMEVideoDecoder(mProxy,
                                                aConfig,
                                                aLayersBackend,
                                                aImageContainer,
                                                aVideoTaskQueue,
                                                wrapper->Callback()));
    return wrapper.forget();
  }

  MOZ_ASSERT(mPDM);
  RefPtr<MediaDataDecoder> decoder(
    mPDM->CreateDecoder(aConfig,
                        aVideoTaskQueue,
                        aCallback,
                        aLayersBackend,
                        aImageContainer));
  if (!decoder) {
    return nullptr;
  }

  RefPtr<MediaDataDecoder> emeDecoder(new EMEDecryptor(decoder,
                                                         aCallback,
                                                         mProxy,
                                                         AbstractThread::GetCurrent()->AsTaskQueue()));
  return emeDecoder.forget();
}