1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130

media / audio / android / opensles_wrapper.cc [blame]

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

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

// The file defines the symbols from OpenSLES that android is using. It then
// loads the library dynamically on first use.

// The openSLES API is using constant as part of the API. This file will define
// proxies for those constants and redefine those when the library is first
// loaded. For this, it need to be able to change their content and so import
// the headers without const.  This is correct because OpenSLES.h is a C API.

// We include stdint.h here as a workaround for an issue caused by the
// #define const below. The inclusion of OpenSLES headers on newer Android NDK
// versions causes stdint.h to be included, which in turn includes __config.
// This causes the declaration of __sanitizer_annotate_contiguous_container to
// not use const parameters, which causes compile issues when building with
// asan. Including here forces __config to be included while const is still
// untouched.
#include <stdint.h>

#include "base/memory/raw_ptr.h"

#define const
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
#undef const

#include <stddef.h>

#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/native_library.h"

// The constants used in chromium. SLInterfaceID is actually a pointer to
// SLInterfaceID_. Those symbols are defined as extern symbols in the OpenSLES
// headers. They will be initialized to their correct values when the library is
// loaded.
SLInterfaceID SL_IID_ENGINE = NULL;
SLInterfaceID SL_IID_ANDROIDSIMPLEBUFFERQUEUE = NULL;
SLInterfaceID SL_IID_ANDROIDCONFIGURATION = NULL;
SLInterfaceID SL_IID_RECORD = NULL;
SLInterfaceID SL_IID_BUFFERQUEUE = NULL;
SLInterfaceID SL_IID_VOLUME = NULL;
SLInterfaceID SL_IID_PLAY = NULL;

namespace {

// The name of the library to load.
const char kOpenSLLibraryName[] = "libOpenSLES.so";

// Loads the OpenSLES library, and initializes all the proxies.
base::NativeLibrary IntializeLibraryHandle() {
  base::NativeLibrary handle =
      base::LoadNativeLibrary(base::FilePath(kOpenSLLibraryName), NULL);
  if (!handle) {
    DLOG(ERROR) << "Unable to load " << kOpenSLLibraryName;
    return NULL;
  }

  // Setup the proxy for each symbol.
  // Attach the symbol name to the proxy address.
  struct SymbolDefinition {
    const char* name;
    raw_ptr<SLInterfaceID> sl_iid;
  };

  // The list of defined symbols.
  const SymbolDefinition kSymbols[] = {
      {"SL_IID_ENGINE", &SL_IID_ENGINE},
      {"SL_IID_ANDROIDSIMPLEBUFFERQUEUE", &SL_IID_ANDROIDSIMPLEBUFFERQUEUE},
      {"SL_IID_ANDROIDCONFIGURATION", &SL_IID_ANDROIDCONFIGURATION},
      {"SL_IID_RECORD", &SL_IID_RECORD},
      {"SL_IID_BUFFERQUEUE", &SL_IID_BUFFERQUEUE},
      {"SL_IID_VOLUME", &SL_IID_VOLUME},
      {"SL_IID_PLAY", &SL_IID_PLAY}};

  for (size_t i = 0; i < sizeof(kSymbols) / sizeof(kSymbols[0]); ++i) {
    void* func_ptr =
        base::GetFunctionPointerFromNativeLibrary(handle, kSymbols[i].name);
    if (!func_ptr) {
      DLOG(ERROR) << "Unable to find symbol for " << kSymbols[i].name;
      return NULL;
    }
    memcpy(kSymbols[i].sl_iid, func_ptr, sizeof(SLInterfaceID));
  }
  return handle;
}

// Returns the handler to the shared library. The library itself will be lazily
// loaded during the first call to this function.
base::NativeLibrary LibraryHandle() {
  // The handle is lazily initialized on the first call.
  static base::NativeLibrary g_handle = IntializeLibraryHandle();
  return g_handle;
}

}  // namespace

// Redefine slCreateEngine symbol.
SLresult slCreateEngine(SLObjectItf* engine,
                        SLuint32 num_options,
                        SLEngineOption* engine_options,
                        SLuint32 num_interfaces,
                        SLInterfaceID* interface_ids,
                        SLboolean* interfaces_required) {
  typedef SLresult (*SlCreateEngineSignature)(SLObjectItf*, SLuint32,
                                              SLEngineOption*, SLuint32,
                                              SLInterfaceID*, SLboolean*);
  base::NativeLibrary handle = LibraryHandle();
  if (!handle)
    return SL_RESULT_INTERNAL_ERROR;

  static SlCreateEngineSignature g_sl_create_engine_handle =
      reinterpret_cast<SlCreateEngineSignature>(
          base::GetFunctionPointerFromNativeLibrary(handle, "slCreateEngine"));
  if (!g_sl_create_engine_handle) {
    DLOG(ERROR) << "Unable to find symbol for slCreateEngine";
    return SL_RESULT_INTERNAL_ERROR;
  }

  return g_sl_create_engine_handle(engine, num_options, engine_options,
                                   num_interfaces, interface_ids,
                                   interfaces_required);
}