chromium/chromecast/media/cma/backend/mixer/post_processor_factory.cc

// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chromecast/media/cma/backend/mixer/post_processor_factory.h"

#include <memory>

#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/scoped_native_library.h"
#include "chromecast/media/audio/audio_log.h"
#include "chromecast/media/cma/backend/mixer/post_processor_paths.h"
#include "chromecast/media/cma/backend/mixer/post_processor_registry.h"
#include "chromecast/media/cma/backend/mixer/post_processors/post_processor_wrapper.h"
#include "chromecast/public/media/audio_post_processor2_shlib.h"
#include "chromecast/public/media/audio_post_processor_shlib.h"

namespace chromecast {
namespace media {

namespace {

const char kV1SoCreateFunction[] = "AudioPostProcessorShlib_Create";
const char kV2SoCreateFunction[] = "AudioPostProcessor2Shlib_Create";
const char kInitLoggingFunction[] = "AudioPostProcessor2Shlib_InitLogging";

base::FilePath FindLibrary(const std::string& library_name) {
  base::FilePath relative_path(library_name);
  base::FilePath full_path = GetPostProcessorDirectory();
  full_path = full_path.Append(relative_path);
  if (base::PathExists(full_path)) {
    return full_path;
  }
  full_path = GetOemPostProcessorDirectory();
  full_path = full_path.Append(relative_path);
  if (base::PathExists(full_path)) {
    return full_path;
  }
  LOG(WARNING) << library_name << " not found in "
               << GetPostProcessorDirectory().AsUTF8Unsafe() << " or "
               << GetOemPostProcessorDirectory().AsUTF8Unsafe()
               << ". Prefer storing post processors in these directories.";
  return relative_path;
}

}  // namespace

using CreatePostProcessor2Function =
    AudioPostProcessor2* (*)(const std::string&, int);

using CreatePostProcessorFunction = AudioPostProcessor* (*)(const std::string&,
                                                            int);

using InitLoggingFunction = void (*)(logging::AudioLogMessage::BufferManager*);

PostProcessorFactory::PostProcessorFactory() = default;
PostProcessorFactory::~PostProcessorFactory() = default;

std::unique_ptr<AudioPostProcessor2> PostProcessorFactory::CreatePostProcessor(
    const std::string& library_name,
    const std::string& config,
    int channels) {
  std::unique_ptr<AudioPostProcessor2> builtin =
      PostProcessorRegistry::Get()->Create(library_name, config, channels);
  if (builtin) {
    LOG(INFO) << "Loaded builtin " << library_name;
    return builtin;
  }

  base::FilePath path = FindLibrary(library_name);
  libraries_.push_back(std::make_unique<base::ScopedNativeLibrary>(path));
  CHECK(libraries_.back()->is_valid())
      << "Could not open post processing library " << path;

  auto init_logging = reinterpret_cast<InitLoggingFunction>(
      libraries_.back()->GetFunctionPointer(kInitLoggingFunction));
  if (init_logging) {
    init_logging(logging::AudioLogMessage::GetBufferManager());
  }

  auto v2_create = reinterpret_cast<CreatePostProcessor2Function>(
      libraries_.back()->GetFunctionPointer(kV2SoCreateFunction));
  if (v2_create) {
    return base::WrapUnique(v2_create(config, channels));
  }

  auto v1_create = reinterpret_cast<CreatePostProcessorFunction>(
      libraries_.back()->GetFunctionPointer(kV1SoCreateFunction));

  DCHECK(v1_create) << "Could not find " << kV1SoCreateFunction << "() in "
                    << library_name;

  LOG(WARNING) << "[Deprecated]: AudioPostProcessor will be deprecated soon."
               << " Please update " << library_name
               << " to AudioPostProcessor2.";

  return std::make_unique<AudioPostProcessorWrapper>(
      base::WrapUnique(v1_create(config, channels)), channels);
}

// static
bool PostProcessorFactory::IsPostProcessorLibrary(
    const base::FilePath& library_path) {
  base::ScopedNativeLibrary library(library_path);
  DCHECK(library.is_valid()) << "Could not open library " << library_path;

  // Check if library is V1 post processor.
  void* v1_create = library.GetFunctionPointer(kV1SoCreateFunction);
  if (v1_create) {
    return true;
  }

  // Check if library is V2 post processor.
  void* v2_create = library.GetFunctionPointer(kV2SoCreateFunction);
  if (v2_create) {
    return true;
  }

  return false;
}

}  // namespace media
}  // namespace chromecast