哪里德尔福/ Android的搜索本地语言库? [英] Where does Delphi/Android search for a native language library?

查看:199
本文介绍了哪里德尔福/ Android的搜索本地语言库?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想补充MIDI功能的Delphi Android应用。 MIDI是通过它可以通过Android NDK访问的SoniVox库中可用。该驱动程序的例子可以发现这里。该驱动程序用C语言编写,与NDK它可以创建可通过一个电话的System.loadLibrary访问的本地语言库。

I want to add MIDI capabilities to Delphi Android apps. MIDI is available via the SoniVox library which can be accessed via the Android NDK. An example of this driver can be found here. The driver is written in C, with the NDK it is possible to create a native language library which can be accessed via a System.loadLibrary call.

  //  MidiDriver - An Android Midi Driver.
  //  Copyright (C) 2013    Bill Farmer
  //  Bill Farmer    william j farmer [at] yahoo [dot] co [dot] uk.

  #include <jni.h>

  // for EAS midi
  #include "eas.h"
  #include "eas_reverb.h"

  // determines how many EAS buffers to fill a host buffer
  #define NUM_BUFFERS 4

  // EAS data
  static EAS_DATA_HANDLE pEASData;
  const S_EAS_LIB_CONFIG *pLibConfig;
  static EAS_PCM *buffer;
  static EAS_I32 bufferSize;
  static EAS_HANDLE midiHandle;

  // init EAS midi
  jint
  Java_org_drivers_midioutput_MidiDriver_init(JNIEnv *env,
                          jobject clazz)
  {
      EAS_RESULT result;

      // get the library configuration
      pLibConfig = EAS_Config();
      if (pLibConfig == NULL || pLibConfig->libVersion != LIB_VERSION)
    return 0;

      // calculate buffer size
      bufferSize = pLibConfig->mixBufferSize * pLibConfig->numChannels *
    NUM_BUFFERS;

      // init library
      if ((result = EAS_Init(&pEASData)) != EAS_SUCCESS)
    return 0;

      // select reverb preset and enable
      EAS_SetParameter(pEASData, EAS_MODULE_REVERB, EAS_PARAM_REVERB_PRESET,
             EAS_PARAM_REVERB_CHAMBER);
      EAS_SetParameter(pEASData, EAS_MODULE_REVERB, EAS_PARAM_REVERB_BYPASS,
             EAS_FALSE);

      // open midi stream
      if (result = EAS_OpenMIDIStream(pEASData, &midiHandle, NULL) !=
    EAS_SUCCESS)
      {
    EAS_Shutdown(pEASData);
    return 0;
      }

      return bufferSize;
  }

  // midi config
  jintArray
  Java_org_drivers_midioutput_MidiDriver_config(JNIEnv *env,
                            jobject clazz)
  {
      jboolean isCopy;

      if (pLibConfig == NULL)
    return NULL;

      jintArray configArray = (*env)->NewIntArray(env, 4);

      jint *config = (*env)->GetIntArrayElements(env, configArray, &isCopy);

      config[0] = pLibConfig->maxVoices;
      config[1] = pLibConfig->numChannels;
      config[2] = pLibConfig->sampleRate;
      config[3] = pLibConfig->mixBufferSize;

      (*env)->ReleaseIntArrayElements(env, configArray, config, 0);

      return configArray;
  }

  // midi render
  jint
  Java_org_drivers_midioutput_MidiDriver_render(JNIEnv *env,
                            jobject clazz,
                            jshortArray shortArray)
  {
      jboolean isCopy;
      EAS_RESULT result;
      EAS_I32 numGenerated;
      EAS_I32 count;
      jsize size;

      // jbyte* GetByteArrayElements(jbyteArray array, jboolean* isCopy)
      // void ReleaseByteArrayElements(jbyteArray array, jbyte* elems,

      // void* GetPrimitiveArrayCritical(JNIEnv*, jarray, jboolean*);
      // void ReleasePrimitiveArrayCritical(JNIEnv*, jarray, void*, jint);

      if (pEASData == NULL)
    return 0;

      buffer =
    (EAS_PCM *)(*env)->GetShortArrayElements(env, shortArray, &isCopy);

      size = (*env)->GetArrayLength(env, shortArray);

      count = 0;
      while (count < size)
      {
    result = EAS_Render(pEASData, buffer + count,
                pLibConfig->mixBufferSize, &numGenerated);
    if (result != EAS_SUCCESS)
        break;

    count += numGenerated * pLibConfig->numChannels;
      }

      (*env)->ReleaseShortArrayElements(env, shortArray, buffer, 0);

      return count;
  }

  // midi write
  jboolean
  Java_org_drivers_midioutput_MidiDriver_write(JNIEnv *env,
                           jobject clazz,
                           jbyteArray byteArray)
  {
      jboolean isCopy;
      EAS_RESULT result;
      jint length;
      EAS_U8 *buf;

      if (pEASData == NULL || midiHandle == NULL)
    return JNI_FALSE;

      buf = (EAS_U8 *)(*env)->GetByteArrayElements(env, byteArray, &isCopy);
      length = (*env)->GetArrayLength(env, byteArray);

      result = EAS_WriteMIDIStream(pEASData, midiHandle, buf, length);

      (*env)->ReleaseByteArrayElements(env, byteArray, buf, 0);

      if (result != EAS_SUCCESS)
    return JNI_FALSE;

      return JNI_TRUE;
  }

  // shutdown EAS midi
  jboolean
  Java_org_drivers_midioutput_MidiDriver_shutdown(JNIEnv *env,
                              jobject clazz)
  {
      EAS_RESULT result;

      if (pEASData == NULL || midiHandle == NULL)
    return JNI_FALSE;

      if ((result = EAS_CloseMIDIStream(pEASData, midiHandle)) != EAS_SUCCESS)
      {
    EAS_Shutdown(pEASData);
    return JNI_FALSE;
      }

      if ((result = EAS_Shutdown(pEASData)) != EAS_SUCCESS)
    return JNI_FALSE;

      return JNI_TRUE;
  }

我创建了一个Android应用程序与Eclipse,增加了MidiDriver作为本机库,并把一切都正常运行。有了这个司机我有我的应用程序MIDI功能。在MidiDriver $ C $的概要C,你会发现下面。

I created an Android app with Eclipse, added the MidiDriver as a native library and got everything up and running. With this driver I have MIDI capabilities in my app. The outline of the MidiDriver code you will find below.

  //  MidiDriver - An Android Midi Driver.
  //  Copyright (C) 2013    Bill Farmer
  //  Bill Farmer    william j farmer [at] yahoo [dot] co [dot] uk.

  package  org.drivers.midioutput;

  import java.io.File;

  import android.media.AudioFormat;
  import android.media.AudioManager;
  import android.media.AudioTrack;
  import android.util.Log;

  // MidiDriver

  public class MidiDriver implements Runnable
  {
      private static final int SAMPLE_RATE = 22050;
      private static final int BUFFER_SIZE = 4096;

      private Thread thread;
      private AudioTrack audioTrack;

      private OnMidiStartListener listener;

      private short buffer[];

      // Constructor

      public MidiDriver ()
      {
         Log.d ("midi", ">> MidiDriver started");
      }

      public void start ()
      {
    // Start the thread
         thread = new Thread (this, "MidiDriver");
         thread.start ();
      } // start //

      @Override
      public void run ()
      {
          processMidi ();
      } // run //

      public void stop ()
      {
        Thread t = thread;
        thread = null;

        // Wait for the thread to exit

        while (t != null && t.isAlive ())
            Thread.yield ();
      } // stop //

      // Process MidiDriver

      private void processMidi ()
      {
        int status = 0;
        int size = 0;

        // Init midi

        if ((size = init()) == 0)
            return;

        buffer = new short [size];

        // Create audio track

        audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, SAMPLE_RATE,
                        AudioFormat.CHANNEL_OUT_STEREO,
                        AudioFormat.ENCODING_PCM_16BIT,
                        BUFFER_SIZE, AudioTrack.MODE_STREAM);
        if (audioTrack == null)
        {
            shutdown ();
            return;
        } // if

        // Call listener

        if (listener != null)
            listener.onMidiStart();

        // Play track

        audioTrack.play();

        // Keep running until stopped

        while (thread != null)
        {
            // Render the audio

            if (render(buffer) == 0)
               break;

            // Write audio to audiotrack

            status = audioTrack.write(buffer, 0, buffer.length);

            if (status < 0)
               break;
        } // while

        // Render and write the last bit of audio

        if (status > 0)
            if (render(buffer) > 0)
               audioTrack.write(buffer, 0, buffer.length);

        // Shut down audio

        shutdown();
        audioTrack.release();
      } // processMidi //

      public void setOnMidiStartListener (OnMidiStartListener l)
      {
         listener = l;
      } // setOnMidiStartListener //

      public static void load_lib (String libName) 
      {
         File file = new File (libName);

         if (file.exists ()) 
         {
             System.load (libName);
         } else 
         {
             System.loadLibrary (libName);
         }
     }    // Listener interface

      public interface OnMidiStartListener
      {
         public abstract void onMidiStart ();
      } // OnMidiStartListener //

      // Native midi methods

      private native int     init ();
      public  native int []  config ();
      private native int     render (short a []);
      public  native boolean write (byte a []);
      private native boolean shutdown ();

      // Load midi library

      static
      {
         System.loadLibrary ("midi");
      }
  }

接下来,我测试了JNI接口,看看是否我可以从德尔福通过JNI Java类一>。也没问题。所以理论上,我应该能够通过Java接口访问MidiDriver:爽!我在一个又一个Java类包裹MidiDriver:MIDI_Output以内部处理接口(我不知道如何连接在Delphi中的Java接口MIDI_Output创建MidiDriver的实例,并从MidiDriver调用的函数必要时,这一切的伟大工程的时候。从Eclipse中运行MIDI_Output的某些部分如下:

Next I tested the JNI interface to see whether I could access Java classes from Delphi via JNI. No problem either. So theoretically I should be able to access the MidiDriver via a Java interface: cool! I wrapped MidiDriver in a another Java class: MIDI_Output in order to handle the interface internally (I have no idea how to interface a Java interface in Delphi. MIDI_Output creates an instance of MidiDriver and calls functions from MidiDriver when necessary. This all works great when running from Eclipse. Some parts of MIDI_Output below:

  package org.drivers.midioutput;

  import java.io.IOException;

  import org.drivers.midioutput.MidiDriver.OnMidiStartListener;

  import android.media.MediaPlayer;
  import android.os.Environment;
  import android.util.Log;

  public class MIDI_Output implements OnMidiStartListener
  {
     protected MidiDriver midi_driver;
     protected MediaPlayer media_player;

     public MIDI_Output ()
     {
        // Create midi driver
        Log.d ("midi", ">> Before initializing MIDI driver version 1");

        midi_driver = new MidiDriver();

  // Set onmidistart listener to this class

        if (midi_driver != null)
            midi_driver.setOnMidiStartListener (this);
     } // MIDI_Output () //

  protected void putShort (int m, int n, int v)
  {
     if (midi_driver != null)
     {
       byte msg [] = new byte [3];

       msg [0] = (byte) m;
       msg [1] = (byte) n;
       msg [2] = (byte) v;

       midi_driver.write (msg);
     } // if
  } // putShort //

  // and much more code
  // ...   

在上面putShort该示例调用从MidiDriver功能写入这是在本机库中定义的函数。这一切工作正常Java编写,但在实践中Dellphi是你可能已经猜到有点困难。为了更详细地显示调用链我需要使用在Delphi这整个玩意儿看到下面的图片。

In the example above putShort calls function write from MidiDriver which is a function defined in the native library. This all works fine in Java but in Dellphi practice is a little harder as you might have guessed. To show in more detail the call chain I need to use this whole contraption in Delphi see the image below.

libsonivox 功能 EAS_WriteMidiStream /系统/ lib目录中) code>可以发现,这是从函数调用 libmidi.so (比比皆是,但也是在 /系统/ lib目录 /供应商/ lib目录),这是在 MidiDriver声明的.java MIDI_Output.apk 这是从 MIDI_Output.java 名为它创建了一个新MidiDriver ,指的是 midi_driver.write(...)函数 putShort 相同的包。最后, putShort 应在Delphi中调用,但它永远不会到达那里。

In libsonivox (found in /system/lib) the function EAS_WriteMidiStream can be found, which is called from function write in libmidi.so (found everywhere, but also in /system/lib and /vendor/lib), which is declared in MidiDriver.java in MIDI_Output.apk which is called from MIDI_Output.java which creates a new MidiDriver and refers to midi_driver.write (...) in function putShort of the same package. Finally putShort should be called in Delphi but it never gets there.

据中止时 MIDI_Output 创建新MidiDriver 它试图加载 MIDI 库。该程序将无法加载库 MIDI 。我跑了 ADB -d logcat的来看看发生了什么和下面的输出显示。这是Android屏幕上显示的错误信息突出显示。

It is aborted when MIDI_Output create the new MidiDriver which tries to load the midi library. The program is not able to load the library "midi". I ran adb -d logcat to see what happens and the output is shown below. The error message that is shown on the android screen is highlighted.

  D/dalvikvm( 5251): DexOpt: --- BEGIN 'MIDI_Output.apk' (bootstrap=0) ---
  D/dalvikvm( 5320): DexOpt: load 50ms, verify+opt 174ms, 1050124 bytes
  D/dalvikvm( 5251): DexOpt: --- END 'MIDI_Output.apk' (success) ---
  D/dalvikvm( 5251): DEX prep '/storage/emulated/legacy/Data/d/MIDI_Output.apk': u
  nzip in 14ms, rewrite 401ms
  W/dalvikvm( 5251): dvmFindClassByName rejecting 'org.drivers.midioutput/MIDI_Out
  put'
  D/midi    ( 5251): >> Before initializing MIDI driver version 1
  W/dalvikvm( 5251): Exception Ljava/lang/UnsatisfiedLinkError; thrown while initi
  alizing Lorg/drivers/midioutput/MidiDriver;

  W/System.err( 5251): java.lang.UnsatisfiedLinkError: Couldn't load midi from loa
  der dalvik.system.DexClassLoader[DexPathList[[zip file "/storage/sdcard0/Data/d/
  MIDI_Output.apk"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]]: findLib
  rary returned null

  W/System.err( 5251):    at java.lang.Runtime.loadLibrary(Runtime.java:358)
  W/System.err( 5251):    at java.lang.System.loadLibrary(System.java:526)
  W/System.err( 5251):    at org.drivers.midioutput.MidiDriver.<clinit>(MidiDriver
  .java:177)
  W/System.err( 5251):    at org.drivers.midioutput.MIDI_Output.<init>(MIDI_Output
  .java:22)
  W/System.err( 5251):    at java.lang.Class.newInstanceImpl(Native Method)
  W/System.err( 5251):    at java.lang.Class.newInstance(Class.java:1208)
  W/System.err( 5251):    at dalvik.system.NativeStart.run(Native Method)
  D/dalvikvm( 5251): GC_FOR_ALLOC freed 795K, 9% free 9091K/9920K, paused 13ms,
  total 13ms
  D/dalvikvm( 5251): GC_CONCURRENT freed 9K, 4% free 9532K/9920K, paused
  2ms+2ms, total 22ms

据我了解,库不能被发现。麻烦的是,我不知道这个库搜索。该错误消息中提到 /供应商/ lib目录 /系统/ lib目录。我添加libmidi.so这些库。我加了库的应用程序目录 com.embarcadero.MIDI_Output_Project / lib目录(这正是Android的存储库),以 /存储/ sdcard0 /数据/ D / (存储包含Java类MIDI_Output.apk的目录)。我从字面上洒在我的Andr​​oid系统libmidi.so。我试图加载 libmidi.so 以及

I understand that the library cannot be found. Trouble is, I do not know where this library is searched. The error message mentions /vendor/lib and /system/lib. I added libmidi.so to these libraries. I added the library to the application directory com.embarcadero.MIDI_Output_Project/lib (that is where android stores the library), to /storage/sdcard0/Data/d/ (the directory where MIDI_Output.apk containing the Java classes are stored). I literally sprinkled my android system with libmidi.so. I have tried to load libmidi.so as well.

作为一个测试,我添加了一个很简单的例子类的MIDI_Output包和调用的函数test_int。这将运行没有任何问题。

As a test I added a very simple example class to the MIDI_Output package and called function test_int. This runs without any problems.

  package org.drivers.midioutput;

  import android.util.Log;

  public class class_test
  {
     public int test_int (int n)
     {
        int sq = n * n;
        String mess = "*** test_int computes " + String.valueOf (sq);

        Log.d ("midi", mess);
        return n * n;
     }
  }

我的问题是:在目录DalvikVM寻找在上述(Delphi调用通过JNI的Java类和Java调用NDK通过C库)

My question is: in which directory is DalvikVM looking for native library in a setup described above (Delphi calling a Java class via JNI and Java calling a C library via NDK)?

第二个问题:它是一个库搜索路径的问题呢?也许德尔福无法通过JNI调用NDK。

A second question: is it a library search path problem at all? Maybe Delphi is not able to call NDK via JNI.

我试图尽可能简短。如果有人认为我应该增加更多的code只是让我知道。任何帮助是极大的AP preciated。

I have tried to be as brief as possible. If anyone thinks I should add more code just let me know. Any help is greatly appreciated.

推荐答案

这是由德尔福使用NDK库应放在&LT;路径您PlatformSDKs&GT; \\ Android的NDK-R8E \\平台\\ Android的14 \\弓臂的\\ usr \\ lib中。我意识到这得益于亚略和克里斯的建议直接使用NDK。在来源大多数Android文件\\ RTL \\机器人目录中包含的文件 Androidapi.inc 包含以下定义

NDK libraries that are used by Delphi should be placed in <path to your PlatformSDKs>\android-ndk-r8e\platforms\android-14\arch-arm\usr\lib. I realised this thanks the recommendations of Arioch and Chris to use the NDK directly. Most android files in the Source\rtl\android directory include the file Androidapi.inc which contains the following definitions

const
    AndroidLib            = '/usr/lib/libandroid.so';
    AndroidJniGraphicsLib = '/usr/lib/libjnigraphics.so';
    AndroidEglLib         = '/usr/lib/libEGL.so';
    AndroidGlesLib        = '/usr/lib/libGLESv1_CM.so';
    AndroidGles2Lib       = '/usr/lib/libGLESv2.so';
    AndroidLogLib         = '/usr/lib/liblog.so';
    AndroidOpenSlesLib    = '/usr/lib/libOpenSLES.so';

目录 / usr / lib目录上的Nexus-7并不存在,但我发现它与在<$ C $声明的所有文件,上面提到的路径C>常量部分。复制 libmidi.so 此目录解决了这个问题。我现在听到任何声音的不那么小问题。我会尽力解决现在的,以及试图直接调用NDK。

The directory /usr/lib does not exist on the Nexus-7 but I found it in the path mentioned above with all the files declared in the const part. Copying the libmidi.so to this directory solved the problem. I now have the not so minor problem of hearing no sound. I'll try to solve that now, as well as trying to call the NDK directly.

这篇关于哪里德尔福/ Android的搜索本地语言库?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆