2011-04-09 2 views
1

Je suis en cours d'exécution dans des problèmes avec mon application Android fermeture (aucune erreur ou quoi que ce soit) lorsque vous essayez d'exécuter le code suivant:JNI byteArray passer l'aide

JNIEXPORT void Java_teamjeff_oggstreamtest_MainTest_audioFunc(JNIEnv* env, jobject obj) { 
//<REMOVED VARIABLE INITIALIZATION> 
    jclass cls = (*env)->GetObjectClass(env, obj); 
    jmethodID writeDataFunc = (*env)->GetMethodID(env, cls, "writeToAudioTrack", "([B)V"); 
    if (!writeDataFunc) return; 
    jmethodID readDataFunc = (*env)->GetMethodID(env, cls, "readFromBuffer", "([B)I"); 
    if (!readDataFunc) return; 

    rawDataRead = (*env)->NewByteArray(env, 4096); 
    bytes = (*env)->CallIntMethod(env, obj,readDataFunc, &rawDataRead); 
    char* carr = (*env)->GetByteArrayElements(env, rawDataRead, NULL); 
    memcpy(buffer, carr, bytes); 
    (*env)->DeleteLocalRef(env, rawDataRead); 
//<REMOVED REST OF FUNCTION> 
} 

J'ai suivi le code « trouble » au bytes = (*env)->CallIntMethod(env, obj,readDataFunc, &rawDataRead); ligne. Si je retourne avant cette ligne, mon application ne se ferme pas, mais si je retourne immédiatement après cette ligne, mon application se ferme aléatoirement sans même une erreur.

Voici le code JAVA:

package teamjeff.oggstreamtest; 

import android.app.Activity; 
import android.media.AudioFormat; 
import android.media.AudioManager; 
import android.media.AudioTrack; 
import android.os.Bundle; 
import android.os.Handler; 
import java.io.IOException; 
import java.net.InetAddress; 
import java.net.Socket; 
import com.Ostermiller.util.CircularByteBuffer; 


public class MainTest extends Activity { 

    public static Handler mHandler = new Handler(); 
    private final CircularByteBuffer cbb = new CircularByteBuffer(1024*512, true); 
    public AudioTrack mAudioTrack; 

    static { 
     System.loadLibrary("vorbis-decoder"); 
    } 

    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 
     try { 

      final Socket test = new Socket(InetAddress.getByName(<HOME SERVER URL>), <PORT>); 

      new Thread(
        new Runnable(){ 
         public void run(){ 
          try { 
           while(!test.isClosed()) { 
            byte[] temp = new byte[4096]; 
            int bytes = test.getInputStream().read(temp, 0, 4096); 
            cbb.getOutputStream().write(temp, 0, bytes); 
           } 
           } catch (Exception e) { 
            e.printStackTrace(); 
           } 
         } 
        } 
       ).start(); 


      mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 
        44100, 
        AudioFormat.CHANNEL_OUT_STEREO, 
        AudioFormat.ENCODING_PCM_16BIT, 
        1024*64, 
        AudioTrack.MODE_STREAM); 
      mAudioTrack.play(); 

      new Thread(new Runnable() { 
       public void run() { 
        audioFunc(); 
       } 
      }).start(); 

     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    public native void audioFunc(); 

    @SuppressWarnings("unused") 
    private void writeToAudioTrack(final byte[] media) { 
     mHandler.post(new Runnable() { 
      public void run() { 
       mAudioTrack.write(media, 0, media.length); 
      } 
     }); 
    } 

    @SuppressWarnings("unused") 
    private int readFromBuffer(byte[] buffer) { 
     try { 
      return cbb.getInputStream().read(buffer, 0, buffer.length); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     return -1; 
    } 

} 

J'ai cherché pendant des jours ici et sur Google sur la façon d'accomplir ce que je veux faire. Mon code ci-dessus est le collage de divers extraits de code que j'ai trouvés sur Internet avec des ajustements pour s'adapter à mon cas d'utilisation.

Ce que je suis en train d'accomplir:

Je lirai dans les données d'une prise dans mon application Android, transmettre ces données à mon code C pour le décodage (si l'algorithme lit en pièce par pièce au cours de la algorithme, ce qui signifie que je ne peux pas passer de byteArray de Java à C et appeler ma fonction C plusieurs fois car le décodeur utilise parfois des données d'octets de lecture précédents). Mon code C fait le décodage, et renvoie les données PCM à mon application Android pour être joué sur un AudioTrack.

J'utilise un tampon circulaire pour mettre en tampon les données du socket.

Lorsque j'essaie de déboguer mon application Android, je mets des points de rupture aux entrées des fonctions de lecture et d'écriture et elles ne semblent jamais être appelées. Est-ce que je fais quelque chose de mal quand je passe le byteArray de mon code C à JAVA pour être rempli avec des données? Dois-je faire cela d'une manière alternative?

Répondre

1

Quelques notes qui pourraient aider.

  1. & La fonction rawDataRead est incorrecte. Perdez le &. Vous venez de passer le ref que vous obtenez, pas l'adresse de celui-ci.

  2. vous n'avez pas besoin de supprimer cette référence locale. Toutes les références locales sont supprimées lorsqu'une fonction native revient. Je suis assez confiant que c'est vrai dans java, mais la situation android peut être différente.

  3. Vous n'avez pas besoin de continuer à récupérer les identifiants de méthode. Vous pouvez les obtenir une fois et accrocher sur eux.

+0

Merci beaucoup. Cela a corrigé mon erreur! Toutefois, mon application a continué à se bloquer lorsque j'ai supprimé les appels DeleteLocalRef() après quelques secondes d'exécution. Quand je les remets, j'obtiens environ 2-3 minutes de lecture avant d'atteindre une limite de mémoire de 24 Mo maximum. Existe-t-il un moyen de libérer davantage de mémoire pendant l'exécution de mon programme? Je ne sais pas pourquoi ces tableaux d'octets ne sont pas libérés par le GC après que j'ai supprimé la référence locale! – someone1

+0

@som Je pense que je pourrais vous citer le chapitre et le verset sur ceci pour * java *. Ce qui m'amène à penser que vous rencontrez quelque chose de spécifique à Android, que je ne peux pas vous aider. – bmargulies

+1

Je l'ai compris. Il s'avère que je manquais de mémoire en mettant en attente des threads de données pour écrire sur l'AudioTrack qui ne s'épuisait pas plus vite que le décodeur décodait (ce que je n'attendais pas étant donné mes autres tests de décodage avec d'autres librairies).J'ai ajouté un contrôle de thread sur le côté JAVA pour bloquer la file d'attente de threads à un montant raisonnable. Merci encore pour votre aide! – someone1

Questions connexes