NullPointerException при записи в экземпляр AudioTrack при обратном вызове из собственного кода - PullRequest
0 голосов
/ 02 марта 2012

Я выполняю некоторый процесс декодирования в собственном коде и вызываю из него Java-метод для записи сэмплов в экземпляр AudioTrack.Процесс декодирования работает нормально, вызывается обратный вызов из собственного кода в Java:

private void writeToAudioTrack(final byte[] buffer)

, но как только объект Runnable начинает записывать сэмплы в AudioTrack, я сразу получаю исключение NullPointerException.Я совершенно уверен, что это вызвано неправильными потоками, но не могу понять, что там не так.Я прилагаю полный код Java:

public class Player
{
    private AudioTrack track;
    private boolean isInitialized = false;
    private static Handler handler = new Handler();

    public void init(String mediaSource)
    {
        // Call native function initEngine
        isInitialized = initEngine(mediaSource);

        if (isInitialized)
        {
            int bufSize = AudioTrack.getMinBufferSize(44100, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);
            track = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, bufSize, AudioTrack.MODE_STREAM);
            track.play();
        }
    }

    public void play()
    {
        // Call native rendering function in a separate thread
        if (isInitialized)
        {
            new Thread(new Runnable()
            {
                @Override
                public void run()
                {
                    renderAudio();
                }
            }).start();
        }
    }

    public void release()
    {
        isInitialized = false;
        releaseEngine();
    }

    // This is callback from native code
    private void writeToAudioTrack(final byte[] buffer)
    {
        handler.post(new Runnable()
        {
            @Override
            public void run()
            {
                try
                {
                    track.write(buffer, 0, buffer.length);
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
            }
        });
    }

    // 
    static
    {
        // Load native library
        System.loadLibrary("decoder");
    }

    // Private native methods
    private static native boolean initEngine(String mediaSource);
    private static native void releaseEngine();
    private static native void renderAudio();

Даже если я создаю буфер вместо блока try-catch:

byte [] buffer = new byte[256];
track.write(buffer, 0, buffer.length);

Я получаю тот же результат - NullPointerException.

Трассировка стека:

java.lang.NullPointerException на com.mautilus.audioplayer.Player $ 2.run (Player.java:99) на android.os.Handler.handleCallback(Handler.java:587) в android.os.Handler.dispatchMessage (Handler.java:92) в android.os.Looper.loop (Looper.java:123) в android.app.ActivityThread.main (ActivityThread.java:4627) на java.lang.reflect.Method.invokeNative (собственный метод) на java.lang.reflect.Method.invoke (Method.java:521) на com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.Java: 876) на com.android.internal.os.ZygoteInit.main (ZygoteInit.java:634) на dalvik.system.NativeStart.main (собственный метод)

Ответы [ 2 ]

1 голос
/ 02 марта 2012

Редактировать:

Чтобы добавить дополнительную защиту, я бы добавил:

if (!isInitialized) {
   return;
}

в начало метода writeToAudioTrack, чтобы убедиться, чточто обратный вызов не вызывается, когда isInitialized равен false.Как зарегистрирован обратный звонок?Вы можете показать этот код?


Возможно, глупый ответ, но в вашем конструкторе, вы уверены, что он не должен быть:

if (!isInitialized) {
    ...
}

Если нет, то вы уверены? что метод run() не вызывается, если isInitialized было возвращено как false из вызова на initEngine?Если это так, то track будет нулевым, что объясняет NPE в методе run().

Простой способ выяснить это - поместить assert в run().:

assertNotNull(trace);

или сделайте правильный тест и бросьте IllegalStateException, если trace равно null.

Единственное, что может вызвать NPE, это если null значение для buffer было передано в метод writeToAudioTrack.Хорошей идеей может быть тестирование null и добавление IllegalArgumentException.

Надеюсь, это поможет.

0 голосов
/ 04 марта 2012

Ошибка была в типе одного из собственных методов - initEngine, в этом случае она не должна быть объявлена ​​как статическая.

Согласно документации:

http://docs.oracle.com/javase/1.4.2/docs/guide/jni/spec/functions.html#wp16660

GetMethodID() вызывает инициализацию неинициализированного класса.Таким образом, если загрузка библиотеки не связана с каким-либо экземпляром класса (это нормально):

static
{
    // Load native library
    System.loadLibrary("decoder");
}

, то собственный код:

jmethodID writeToAudioTrackMethodID = NULL;
jclass cls = (*env)->FindClass(env, "com.mautilus.audioplayer.Player");

if (!cls)
writeToAudioTrackMethodID = (*env)->GetMethodID(env, cls, "writeToAudioTrack", "([B)V");

вызывается из статического метода - initEngine inв моем случае не удается получить какой-либо существующий экземпляр класса (даже если такой экземпляр существует) и создает новый (с полями, инициализированными по умолчанию) - вот и все ...

...