2011-04-09 5 views
1

내가 (오류없이 또는 아무것도) 다음 코드를 실행하려고 할 때 닫는 내 안드로이드 앱 문제로 실행되었습니다 난에 "문제"코드를 추적 한JNI BYTEARRAY 통과 도움

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> 
} 

bytes = (*env)->CallIntMethod(env, obj,readDataFunc, &rawDataRead); 행. 이 줄 앞에서 돌아 오면 내 앱이 닫히지 않지만이 줄 바로 다음에 돌아 오면 오류없이 앱이 임의로 닫힙니다.

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; 
    } 

} 

내가 일 여기 내가하고 원하는 작업을 수행하는 방법에 대한 Google에서 검색 한 다음은

는 자바 코드입니다. 위의 코드는 인터넷에서 발견 된 다양한 코드 스 니펫을 함께 사용하여 사용 사례에 맞게 조정 한 것입니다.

내가 달성하기 위해 노력하고있어 : 알고리즘이 중에 조각으로 조각을 읽어하지만 내 안드로이드 응용 프로그램의 소켓에서 데이터를 읽어

(디코딩에 내 C 코드에이 데이터를 전달 알고리즘, 자바에서 byteArray를 C로 전달할 수없고, 디코더가 때때로 이전의 읽기 바이트에서 데이터를 사용하기 때문에 여러 번 C 함수를 호출 할 수 없다는 것을 의미합니다. 내 C 코드가 디코딩을 수행하고 AudioTrack에서 재생할 PCM 데이터를 다시 Android 앱에 전달합니다.

소켓의 데이터를 버퍼링하는 순환 버퍼를 사용하고 있습니다.

Android 앱을 디버깅하려고 할 때 항목의 읽기 및 쓰기 기능에 중단 점을 설정 했으므로 절대로 호출되지 않습니다.

byteArray를 C 코드에서 JAVA로 데이터를 채울 때 뭔가 잘못하고 있습니까? 이 방법을 다른 방법으로 수행해야합니까?

답변

1

몇 가지 메모가 도움이 될 수 있습니다.

  1. & rawDataRead가 잘못되었습니다. &을 잃어 버리십시오. 당신은 당신이 얻는 심판을 그냥 전달합니다.

  2. 해당 로컬 참조를 삭제하지 않아도됩니다. 네이티브 함수가 반환되면 모든 로컬 참조가 삭제됩니다. 나는 이것이 에서 사실이라고 확신하지만, 안드로이드 상황은 다를 수 있습니다.

  3. 메소드 ID는 계속 가져올 필요가 없습니다. 당신은 그들을 한 번 붙잡고 그들 위에 매 달릴 수 있습니다.

+0

정말 고마워요. 그게 내 실수를 고쳤어! 그러나 몇 초 동안 실행 한 후에 DeleteLocalRef() 호출을 제거하면 응용 프로그램이 계속 충돌합니다. 내가 24MB 최대 메모리 제한의 일종을 공격하기 전에 내가 다시 그들을 넣어 때 재생 약 2-3 분. 내 프로그램을 실행하는 동안 메모리를 더 확보 할 수있는 방법이 있습니까? 로컬 참조를 삭제 한 후 GC가이 바이트 배열을 해제하지 않는 이유를 모르겠습니다! – someone1

+0

@som 나는 * java *에 대한 장과 절을 인용 할 수 있다고 생각한다. 그래서 내가 너를 도울 수없는 안드로이드 만의 특별한 경험을하고 있다고 생각하게 만든다. – bmargulies

+1

나는 그것을 이해했다. 밖으로 디코더 (내가 사용했던 다른 라이브러리에서 내 다른 디코딩 테스트를 받았다고 기대하지 않았던 것)보다 빨리 소모하지 않는 AudioTrack에 쓰려고 데이터 스레드를 대기시켜 메모리가 부족합니다.합리적인 양의 큐 대기열을 차단하기 위해 자바 측에 스레드 컨트롤을 추가했습니다. 모든 도움을 주셔서 다시 한 번 감사드립니다! – someone1