Google Play New problem : 64bits

All topics about ZGameEditor goes here.

Moderator: Moderators

User avatar
VilleK
Site Admin
Posts: 2357
Joined: Mon Jan 15, 2007 4:50 pm
Location: Stockholm, Sweden
Contact:

Re: Google Play New problem : 64bits

Post by VilleK »

Try printing the bufferSizeInBytes value after it is assigned in ZPlatform_Android.

Platform_error('audio buffer size: ' + inttostr(bufferSizeInBytes));
User avatar
VilleK
Site Admin
Posts: 2357
Joined: Mon Jan 15, 2007 4:50 pm
Location: Stockholm, Sweden
Contact:

Re: Google Play New problem : 64bits

Post by VilleK »

Also I just noticed the constant to choose stereo is 12 and not 2: https://developer.android.com/reference ... OUT_STEREO

So you could try changing 2 to 12 like this:

Code: Select all

  bufferSizeInBytes := Env^.CallStaticIntMethodV(env, cAudioTrack, mGetMinBufferSize, C([AudioPlayer.AudioRate, 3, 12]));

  track := env^.NewObjectV(env, cAudioTrack, mAudioTrack, C([3, AudioPlayer.AudioRate, 3, 12, bufferSizeInBytes, 1]));
User avatar
Ats
Posts: 768
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: Google Play New problem : 64bits

Post by Ats »

Weird. The bufferSizeInBytes should be logged...
Here's the full function with the traces:

Code: Select all

{$IFDEF CPU64}
function AudioCallback(P : pointer): Int64;
{$ELSE}
function AudioCallback(P : pointer): LongInt;
{$ENDIF}
const
  OnePassSize = 512;
var
  Env : PJNIEnv;
  cAudioTrack : jclass;
  mGetMinBufferSize, mAudioTrack, mPlay, mStop, mRelease, mWrite : JMethodID;
  bufferSizeInBytes : integer;
  track : jobject;
  buffer : jarray;
  Params : array[0..10] of integer;
  PBuffer : pointer;
  IsCopy : JBoolean;
  CurrentFrameNumber: Integer; // Add frame number variable

  function C(const args : array of const) : pointer;
  var
    I : integer;
  begin
     for I := 0 to High(args) do
       Params[I] := args[I].vinteger;
     Result := @Params;
  end;

begin
  Platform_error('AudioCallback: Audio callback started');
  Result := 0;

  if CurVM = nil then
  begin
    Platform_error('AudioCallback: CurVM is not initialized in AudioCallback');
    Exit;
  end;

  if CurVM^.AttachCurrentThread(CurVM, @Env, nil) <> 0 then
  begin
    Platform_error('AudioCallback: Error attaching thread to JVM');
    Exit;
  end;

  env^.PushLocalFrame(env, 2);

  cAudioTrack := env^.FindClass(env, 'android/media/AudioTrack');
  if cAudioTrack = nil then
  begin
    Platform_error('AudioCallback: no audiotrack');
    Exit;
  end
  else
  begin
    Platform_error(PChar('AudioCallback: AudioTrack class found'));
  end;

  mGetMinBufferSize := env^.GetStaticMethodID(env, cAudioTrack, 'getMinBufferSize', '(III)I');
  if mGetMinBufferSize = nil then 
  begin
    Platform_error('AudioCallback: getMinBufferSize method not found');
    Exit;
  end
  else
  begin
    Platform_error(PChar('AudioCallback: getMinBufferSize method found'));
  end;

  mAudioTrack := env^.GetMethodID(env, cAudioTrack, '<init>', '(IIIIII)V');
  mPlay := env^.GetMethodID(env, cAudioTrack, 'play', '()V');
  mStop := env^.GetMethodID(env, cAudioTrack, 'stop', '()V');
  mRelease := env^.GetMethodID(env, cAudioTrack, 'release', '()V');
  mWrite := env^.GetMethodID(env, cAudioTrack, 'write', '([BII)I');

  Platform_error(PChar('AudioCallback: AudioRate: ' + IntToStr(AudioPlayer.AudioRate) + ', Params: 3, 2'));
  bufferSizeInBytes := Env^.CallStaticIntMethodV(env, cAudioTrack, mGetMinBufferSize, C([AudioPlayer.AudioRate, 3, 2]));

Platform_error(PChar('!!!!!!!!! AudioCallback: Buffer size in bytes: ' + IntToStr(bufferSizeInBytes)));

  if bufferSizeInBytes < 0 then
  begin
    Platform_error(PChar('AudioCallback: Error: getMinBufferSize returned a negative value: ' + IntToStr(bufferSizeInBytes)));
  end
  else
  begin
    Platform_error(PChar('AudioCallback: Buffer size in bytes: ' + IntToStr(bufferSizeInBytes)));
  end;

  track := env^.NewObjectV(env, cAudioTrack, mAudioTrack, C([3, AudioPlayer.AudioRate, 3, 2, bufferSizeInBytes, 1]));
  if track = nil then
  begin
    Platform_error('AudioCallback: could not create track');
    Exit;
  end
  else
  begin
    env^.CallNonvirtualVoidMethod(env, track, cAudioTrack, mPlay);

    buffer := env^.NewByteArray(env, bufferSizeInBytes);
    CurrentFrameNumber := 0; // Initialize frame number

    while not AudioTerminated do
    begin
      PBuffer := env^.GetPrimitiveArrayCritical(env, buffer, IsCopy);
      if PBuffer = nil then
      begin
        Platform_error('AudioCallback: Could not get primitive array critical');
        Break; // Exit the loop if critical array retrieval fails
      end;

      // Mix audio data
      MixAndCopyData(PBuffer, OnePassSize);

      // Release the primitive array
      env^.ReleasePrimitiveArrayCritical(env, buffer, PBuffer, 0);

      // Write the audio data to the track
      env^.CallNonvirtualIntMethodV(env, track, cAudioTrack, mWrite, C([buffer, 0, OnePassSize]));

      // Check for JNI exceptions
      if env^.ExceptionCheck(env) <> 0 then
      begin
        env^.ExceptionDescribe(env); // Log the exception
        env^.ExceptionClear(env); // Clear the exception
        Platform_error('AudioCallback: Error writing audio data due to an exception');
        Break; // Exit the loop on error
      end;

      // Log the current frame number
      Platform_error(PChar('AudioCallback: Processed audio frame: ' + IntToStr(CurrentFrameNumber))); 
      Inc(CurrentFrameNumber); // Increment the frame number for the next log entry

      // Sleep briefly to prevent sound breaking up
      Platform_Sleep(1);
    end;

    env^.CallNonvirtualVoidMethod(env, track, cAudioTrack, mStop);
    env^.CallNonvirtualVoidMethod(env, track, cAudioTrack, mRelease);
  end;

  Env^.PopLocalFrame(Env, nil);
  CurVM^.DetachCurrentThread(CurVM);
end;
If I use:
bufferSizeInBytes := Env^.CallStaticIntMethodV(env, cAudioTrack, mGetMinBufferSize, C([AudioPlayer.AudioRate, 3, 2]));
track := env^.NewObjectV(env, cAudioTrack, mAudioTrack, C([3, AudioPlayer.AudioRate, 3, 2, bufferSizeInBytes, 1]));

It only logs:

Code: Select all

10-08 12:25:40.322 26588 26639 E ZgeAndroid: AudioCallback: Audio callback started
10-08 12:25:40.323 26588 26639 E ZgeAndroid: AudioCallback: AudioTrack class found
10-08 12:25:40.323 26588 26639 E ZgeAndroid: AudioCallback: getMinBufferSize method found
10-08 12:25:40.323 26588 26639 E ZgeAndroid: AudioCallback: AudioRate: 44100, Params: 3, 2
But if I use:
bufferSizeInBytes := Env^.CallStaticIntMethodV(env, cAudioTrack, mGetMinBufferSize, C([AudioPlayer.AudioRate, 3, 12]));
track := env^.NewObjectV(env, cAudioTrack, mAudioTrack, C([3, AudioPlayer.AudioRate, 3, 12, bufferSizeInBytes, 1]));

It doesn't log anything regarding AudioCallback...

I also tried setting
env^.PushLocalFrame(env, 12); (instead of 2)
But I don't know if that's related
User avatar
VilleK
Site Admin
Posts: 2357
Joined: Mon Jan 15, 2007 4:50 pm
Location: Stockholm, Sweden
Contact:

Re: Google Play New problem : 64bits

Post by VilleK »

Seems it is the "C" function that converts arguments that does not work on 64-bits.

Please try the attached changes to jni.pas and ZPlatform_Android.inc.
Attachments
android_changes.zip
(10.44 KiB) Downloaded 6 times
User avatar
Ats
Posts: 768
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: Google Play New problem : 64bits

Post by Ats »

Sorry, your changes are not working. So I added them to the full log version. And added a few more things to log during sound initialization.

Code: Select all

{$IFDEF CPU64}
function AudioCallback(P : pointer): Int64;
{$ELSE}
function AudioCallback(P : pointer): LongInt;
{$ENDIF}
const
  OnePassSize = 512;
var
  Env : PJNIEnv;
  cAudioTrack : jclass;
  mGetMinBufferSize, mAudioTrack, mPlay, mStop, mRelease, mWrite : JMethodID;
  bufferSizeInBytes : integer;
  track : jobject;
  buffer : jarray;
  //Params : array[0..10] of integer;
  PBuffer : pointer;
  IsCopy : JBoolean;
  CurrentFrameNumber: Integer; // Add frame number variable

//  function C(const args : array of const) : pointer;
//  var
//    I : integer;
//  begin
//     for I := 0 to High(args) do
//       Params[I] := args[I].vinteger;
//     Result := @Params;
//  end;

begin
  Platform_error('AudioCallback: Audio callback started');
  Result := 0;

  if CurVM = nil then
  begin
    Platform_error('AudioCallback: CurVM is not initialized in AudioCallback');
    Exit;
  end;

  if CurVM^.AttachCurrentThread(CurVM, @Env, nil) <> 0 then
  begin
    Platform_error('AudioCallback: Error attaching thread to JVM');
    Exit;
  end;

  env^.PushLocalFrame(env, 2);

  cAudioTrack := env^.FindClass(env, 'android/media/AudioTrack');
  if cAudioTrack = nil then
  begin
    Platform_error('AudioCallback: no audiotrack');
    Exit;
  end
  else
  begin
    Platform_error(PChar('AudioCallback: AudioTrack class found'));
  end;

  mGetMinBufferSize := env^.GetStaticMethodID(env, cAudioTrack, 'getMinBufferSize', '(III)I');
  if mGetMinBufferSize = nil then 
  begin
    Platform_error('AudioCallback: getMinBufferSize method not found');
    Exit;
  end
  else
  begin
    Platform_error(PChar('AudioCallback: getMinBufferSize = ' + IntToStr(PtrUInt(mGetMinBufferSize))));
  end;

  // Get the constructor method ID for AudioTrack
  mAudioTrack := env^.GetMethodID(env, cAudioTrack, '<init>', '(IIIIII)V');
  if mAudioTrack = nil then
  begin
    Platform_error('AudioCallback: AudioTrack constructor (<init>) not found');
    Exit;
  end
  else
  begin
    Platform_error(PChar('AudioCallback: AudioTrack constructor ID = ' + IntToStr(PtrUInt(mAudioTrack))));
  end;

  // Get the play method ID
  mPlay := env^.GetMethodID(env, cAudioTrack, 'play', '()V');
  if mPlay = nil then
  begin
    Platform_error('AudioCallback: play method not found');
    Exit;
  end
  else
  begin
    Platform_error(PChar('AudioCallback: play method ID = ' + IntToStr(PtrUInt(mPlay))));
  end;

  // Get the stop method ID
  mStop := env^.GetMethodID(env, cAudioTrack, 'stop', '()V');
  if mStop = nil then
  begin
    Platform_error('AudioCallback: stop method not found');
    Exit;
  end
  else
  begin
    Platform_error(PChar('AudioCallback: stop method ID = ' + IntToStr(PtrUInt(mStop))));
  end;

  // Get the release method ID
  mRelease := env^.GetMethodID(env, cAudioTrack, 'release', '()V');
  if mRelease = nil then
  begin
    Platform_error('AudioCallback: release method not found');
    Exit;
  end
  else
  begin
    Platform_error(PChar('AudioCallback: release method ID = ' + IntToStr(PtrUInt(mRelease))));
  end;

  // Get the write method ID
  mWrite := env^.GetMethodID(env, cAudioTrack, 'write', '([BII)I');
  if mWrite = nil then
  begin
    Platform_error('AudioCallback: write method not found');
    Exit;
  end
  else
  begin
    Platform_error(PChar('AudioCallback: write method ID = ' + IntToStr(PtrUInt(mWrite))));
  end;


  Platform_error(PChar('AudioCallback: AudioRate: ' + IntToStr(AudioPlayer.AudioRate) + ', Params: 3, 12'));
  //bufferSizeInBytes := Env^.CallStaticIntMethodV(env, cAudioTrack, mGetMinBufferSize, C([AudioPlayer.AudioRate, 3, 2]));

Platform_error(PChar('Is CallStaticIntMethodV working?'));
  bufferSizeInBytes := Env^.CallStaticIntMethodV(env, cAudioTrack, mGetMinBufferSize, AudioPlayer.AudioRate, 3, 12);
Platform_error(PChar('CallStaticIntMethodV is working'));


Platform_error(PChar('!!!!!!!!! AudioCallback: Buffer size in bytes: ' + IntToStr(bufferSizeInBytes)));

  if bufferSizeInBytes < 0 then
  begin
    Platform_error(PChar('AudioCallback: Error: getMinBufferSize returned a negative value: ' + IntToStr(bufferSizeInBytes)));
  end
  else
  begin
    Platform_error(PChar('AudioCallback: Buffer size in bytes: ' + IntToStr(bufferSizeInBytes)));
  end;

  //track := env^.NewObjectV(env, cAudioTrack, mAudioTrack, C([3, AudioPlayer.AudioRate, 3, 2, bufferSizeInBytes, 1]));
  track := env^.NewObjectV(env, cAudioTrack, mAudioTrack, 3, AudioPlayer.AudioRate, 3, 12, bufferSizeInBytes, 1);

  if track = nil then
  begin
    Platform_error('AudioCallback: could not create track');
    Exit;
  end
  else
  begin
    env^.CallNonvirtualVoidMethod(env, track, cAudioTrack, mPlay);

    buffer := env^.NewByteArray(env, bufferSizeInBytes);
    CurrentFrameNumber := 0; // Initialize frame number

    while not AudioTerminated do
    begin
      PBuffer := env^.GetPrimitiveArrayCritical(env, buffer, IsCopy);
      if PBuffer = nil then
      begin
        Platform_error('AudioCallback: Could not get primitive array critical');
        Break; // Exit the loop if critical array retrieval fails
      end;

      // Mix audio data
      MixAndCopyData(PBuffer, OnePassSize);

      // Release the primitive array
      env^.ReleasePrimitiveArrayCritical(env, buffer, PBuffer, 0);

      // Write the audio data to the track
      //env^.CallNonvirtualIntMethodV(env, track, cAudioTrack, mWrite, C([buffer, 0, OnePassSize]));
      env^.CallNonvirtualIntMethodV(env, track, cAudioTrack, mWrite, buffer, 0, OnePassSize);

      // Check for JNI exceptions
      if env^.ExceptionCheck(env) <> 0 then
      begin
        env^.ExceptionDescribe(env); // Log the exception
        env^.ExceptionClear(env); // Clear the exception
        Platform_error('AudioCallback: Error writing audio data due to an exception');
        Break; // Exit the loop on error
      end;

      // Log the current frame number
      Platform_error(PChar('AudioCallback: Processed audio frame: ' + IntToStr(CurrentFrameNumber))); 
      Inc(CurrentFrameNumber); // Increment the frame number for the next log entry

      // Sleep briefly to prevent sound breaking up
      Platform_Sleep(1);
    end;

    env^.CallNonvirtualVoidMethod(env, track, cAudioTrack, mStop);
    env^.CallNonvirtualVoidMethod(env, track, cAudioTrack, mRelease);
  end;

  Env^.PopLocalFrame(Env, nil);
  CurVM^.DetachCurrentThread(CurVM);
end;
it seems to hang on that line without a warning or anything, then continue with its life outside of AudioCallback:
bufferSizeInBytes := Env^.CallStaticIntMethodV(env, cAudioTrack, mGetMinBufferSize, AudioPlayer.AudioRate, 3, 12);

Code: Select all

10-08 14:39:55.367  1606  1606 E ZgeAndroid: TZApplication.Run: Initializing application...
10-08 14:39:55.367  1606  1606 E ZgeAndroid: Platform_LoadModule: Loading module: libGLESv1_CM.so
10-08 14:39:55.367  1606  1606 E ZgeAndroid: Platform_LoadModule: Module loaded successfully: libGLESv1_CM.so, Handle: 10156707755351908853
10-08 14:39:55.368  1606  1606 E ZgeAndroid: Platform_LoadModule: JNI_OnLoad function not found.
10-08 14:39:55.369  1606  1606 E ZgeAndroid: TZApplication.Run: Skipping initial tree update to avoid triggering AppState.OnStart.
10-08 14:39:55.369  1606  1606 E ZgeAndroid: TZApplication.Run: Executing OnLoaded commands...
10-08 14:39:55.369  1606  1606 E ZgeAndroid: TExpAddToPointer.Execute: Starting execution
10-08 14:39:55.369  1606  1606 E ZgeAndroid: TExpAddToPointer.Execute: Popped value V: 32
10-08 14:39:55.369  1606  1606 E ZgeAndroid: TExpAddToPointer.Execute: Popped pointer P: 416DCA00
10-08 14:39:55.369  1606  1606 E ZgeAndroid: TExpAddToPointer.Execute: Incremented pointer P: 416DCA20
10-08 14:39:55.369  1606  1606 E ZgeAndroid: TExpAddToPointer.Execute: Pushed updated pointer back to stack
10-08 14:39:55.369  1606  1606 E ZgeAndroid: PLAY SOUND?
10-08 14:39:55.369  1606  1606 E ZgeAndroid: TZApplication.Run: Running main application loop...
10-08 14:39:55.369  1606  1606 E ZgeAndroid: TZApplication.Run: Application run completed.
10-08 14:39:55.369  1606  1606 E ZgeAndroid: GLBase: 1.1
10-08 14:39:55.371  1606  1646 E ZgeAndroid: AudioCallback: Audio callback started
10-08 14:39:55.371  1606  1646 E ZgeAndroid: AudioCallback: AudioTrack class found
10-08 14:39:55.371  1606  1646 E ZgeAndroid: AudioCallback: getMinBufferSize = 1912639840
10-08 14:39:55.371  1606  1646 E ZgeAndroid: AudioCallback: AudioTrack constructor ID = 1912639392
10-08 14:39:55.371  1606  1646 E ZgeAndroid: AudioCallback: play method ID = 1912643488
10-08 14:39:55.371  1606  1646 E ZgeAndroid: AudioCallback: stop method ID = 1912644608
10-08 14:39:55.371  1606  1646 E ZgeAndroid: AudioCallback: release method ID = 1912643776
10-08 14:39:55.371  1606  1646 E ZgeAndroid: AudioCallback: write method ID = 1912644736
10-08 14:39:55.371  1606  1646 E ZgeAndroid: AudioCallback: AudioRate: 44100, Params: 3, 12
10-08 14:39:55.371  1606  1646 E ZgeAndroid: Is CallStaticIntMethodV working?
10-08 14:39:55.483  1606  1648 E ZgeAndroid: Platform_LoadModule: Loading module: libGLESv1_CM.so
10-08 14:39:55.484  1606  1648 E ZgeAndroid: Platform_LoadModule: Module loaded successfully: libGLESv1_CM.so, Handle: 10156707755351908853
10-08 14:39:55.484  1606  1648 E ZgeAndroid: Platform_LoadModule: JNI_OnLoad function not found.
10-08 14:39:55.495  1606  1648 E ZgeAndroid: TZApplication.Main: Current time: 0.4950299859
10-08 14:39:55.495  1606  1648 E ZgeAndroid: TZApplication.Main: Frame processing initiated
10-08 14:39:55.495  1606  1648 E ZgeAndroid: TZApplication.Main: UpdateTime called
10-08 14:39:55.495  1606  1648 E ZgeAndroid: MainSlice: Starting main update cycle
10-08 14:39:55.495  1606  1648 E ZgeAndroid: MainSlice: No current music to update
10-08 14:39:55.495  1606  1648 E ZgeAndroid: MainSlice: No current state to update
10-08 14:39:55.495  1606  1648 E ZgeAndroid: MainSlice: Executing OnUpdate commands
So I tried to manualy set a size for it:
bufferSizeInBytes := 2048;

Then it hangs on
track := env^.NewObjectV(env, cAudioTrack, mAudioTrack, 3, AudioPlayer.AudioRate, 3, 12, bufferSizeInBytes, 1);

So all the problems seems to be coming from jni.pas

And if i set
track := nil;

then the app doesn't crash, but I suppose that is normal :lol:
User avatar
VilleK
Site Admin
Posts: 2357
Joined: Mon Jan 15, 2007 4:50 pm
Location: Stockholm, Sweden
Contact:

Re: Google Play New problem : 64bits

Post by VilleK »

Ok, let's keep trying and focus on jni.

1. Undo the changes to the two files that I suggested.
2. Then change the CallStaticIntMethodV to CallStaticIntMethodA like this:

Code: Select all

  bufferSizeInBytes := Env^.CallStaticIntMethodA(env, cAudioTrack, mGetMinBufferSize, C([AudioPlayer.AudioRate, 3, 2]));
User avatar
Ats
Posts: 768
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: Google Play New problem : 64bits

Post by Ats »

With this:

Code: Select all

  bufferSizeInBytes := Env^.CallStaticIntMethodA(env, cAudioTrack, mGetMinBufferSize, C([AudioPlayer.AudioRate, 3, 2]));
  //bufferSizeInBytes := 2048;
  Platform_error(PChar('CallStaticIntMethodA is working'));

  if bufferSizeInBytes < 0 then
  begin
    Platform_error(PChar('AudioCallback: Error: getMinBufferSize returned a negative value: ' + IntToStr(bufferSizeInBytes)));
  end
  else
  begin
    Platform_error(PChar('AudioCallback: Buffer size in bytes: ' + IntToStr(bufferSizeInBytes)));
  end;
I get:

Code: Select all

10-09 09:57:56.734 13367 13410 E ZgeAndroid: CallStaticIntMethodA is working
10-09 09:57:56.734 13367 13410 E ZgeAndroid: AudioCallback: Error: getMinBufferSize returned a negative value: -2
Just in case, I also tried with 12 instead of 2, the result is the same.

Edit:
ChatGPT made me modified C function so Params is an array of JValue instead of integer:

Code: Select all

var
  Params : array[0..2] of JValue; 

  function C(const args: array of const): PJValue;
  var
    I: Integer;
  begin
    for I := 0 to High(args) do
    begin
      case args[I].VType of
        vtInteger: Params[I].i := args[I].VInteger;  // Map to JValue.i for integers
        // Handle other types (if needed) like vtExtended, vtPointer, etc.
      else
        raise Exception.Create('Unsupported argument type');
      end;
    end;
    Result := @Params;
  end;
Now the trace works: AudioCallback: Buffer size in bytes: 1772
But then it hangs on NewObjectV.
Last edited by Ats on Wed Oct 09, 2024 8:19 am, edited 2 times in total.
User avatar
VilleK
Site Admin
Posts: 2357
Joined: Mon Jan 15, 2007 4:50 pm
Location: Stockholm, Sweden
Contact:

Re: Google Play New problem : 64bits

Post by VilleK »

Try changing to NewObjectA.
User avatar
Ats
Posts: 768
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: Google Play New problem : 64bits

Post by Ats »

That's what I was doing.
track := env^.NewObjectA(env, cAudioTrack, mAudioTrack, C([3, AudioPlayer.AudioRate, 3, 2, bufferSizeInBytes, 1]));

It traces that NewObjectA is working, but nothing else afterward, and no sound. Maybe I need to add more traces for buffer and PBuffer?

Code: Select all

  track := env^.NewObjectA(env, cAudioTrack, mAudioTrack, C([3, AudioPlayer.AudioRate, 3, 2, bufferSizeInBytes, 1]));
  Platform_error(PChar('NewObjectA is working'));

  if track = nil then
  begin
    Platform_error('AudioCallback: could not create track');
    Exit;
  end
  else
  begin
    env^.CallNonvirtualVoidMethod(env, track, cAudioTrack, mPlay);

    buffer := env^.NewByteArray(env, bufferSizeInBytes);
    CurrentFrameNumber := 0; // Initialize frame number

    while not AudioTerminated do
    begin
      PBuffer := env^.GetPrimitiveArrayCritical(env, buffer, IsCopy);
      if PBuffer = nil then
      begin
        Platform_error('AudioCallback: Could not get primitive array critical');
        Break; // Exit the loop if critical array retrieval fails
      end;

      // Mix audio data
      MixAndCopyData(PBuffer, OnePassSize);

      // Release the primitive array
      env^.ReleasePrimitiveArrayCritical(env, buffer, PBuffer, 0);

      // Write the audio data to the track
      //env^.CallNonvirtualIntMethodV(env, track, cAudioTrack, mWrite, C([buffer, 0, OnePassSize]));
      env^.CallNonvirtualIntMethodV(env, track, cAudioTrack, mWrite, buffer, 0, OnePassSize);

      // Check for JNI exceptions
      if env^.ExceptionCheck(env) <> 0 then
      begin
        env^.ExceptionDescribe(env); // Log the exception
        env^.ExceptionClear(env); // Clear the exception
        Platform_error('AudioCallback: Error writing audio data due to an exception');
        Break; // Exit the loop on error
      end;

      // Log the current frame number
      Platform_error(PChar('AudioCallback: Processed audio frame: ' + IntToStr(CurrentFrameNumber))); 
      Inc(CurrentFrameNumber); // Increment the frame number for the next log entry

      // Sleep briefly to prevent sound breaking up
      Platform_Sleep(1);
    end;

    env^.CallNonvirtualVoidMethod(env, track, cAudioTrack, mStop);
    env^.CallNonvirtualVoidMethod(env, track, cAudioTrack, mRelease);
  end;

  Env^.PopLocalFrame(Env, nil);
  CurVM^.DetachCurrentThread(CurVM);
end;
User avatar
Ats
Posts: 768
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: Google Play New problem : 64bits

Post by Ats »

All right, I added MANY traces :lol:

Code: Select all

10-09 11:00:45.280 24827 24873 E ZgeAndroid: AudioCallback: Audio callback started
10-09 11:00:45.281 24827 24873 E ZgeAndroid: AudioCallback: AudioTrack class found
10-09 11:00:45.281 24827 24873 E ZgeAndroid: AudioCallback: getMinBufferSize = 1908551640
10-09 11:00:45.281 24827 24873 E ZgeAndroid: AudioCallback: AudioTrack constructor ID = 1908550744
10-09 11:00:45.281 24827 24873 E ZgeAndroid: AudioCallback: play method ID = 1908555256
10-09 11:00:45.281 24827 24873 E ZgeAndroid: AudioCallback: stop method ID = 1908556376
10-09 11:00:45.281 24827 24873 E ZgeAndroid: AudioCallback: release method ID = 1908555544
10-09 11:00:45.281 24827 24873 E ZgeAndroid: AudioCallback: write method ID = 1908556504
10-09 11:00:45.281 24827 24873 E ZgeAndroid: AudioCallback: AudioRate: 44100, Params: 3, 12
10-09 11:00:45.281 24827 24873 E ZgeAndroid: AudioCallback: Is CallStaticIntMethodV working?
10-09 11:00:45.290 24827 24873 E ZgeAndroid: AudioCallback: CallStaticIntMethodV is working
10-09 11:00:45.290 24827 24873 E ZgeAndroid: AudioCallback: Buffer size in bytes: 1772
10-09 11:00:45.290 24827 24873 E ZgeAndroid: AudioCallback: Is NewObjectA working?
10-09 11:00:45.305 24827 24873 E ZgeAndroid: AudioCallback: NewObjectA is working
10-09 11:00:45.305 24827 24873 E ZgeAndroid: AudioCallback: Calling play method on track object: 488865526293
10-09 11:00:45.317 24827 24873 E ZgeAndroid: AudioCallback: play method called successfully on track object: 488865526293
10-09 11:00:45.317 24827 24873 E ZgeAndroid: AudioCallback: Creating new byte array with size: 1772
10-09 11:00:45.317 24827 24873 E ZgeAndroid: AudioCallback: Byte array created successfully, buffer reference: 488865526309
10-09 11:00:45.317 24827 24873 E ZgeAndroid: AudioCallback: Calculate PBuffer
10-09 11:00:45.317 24827 24873 E ZgeAndroid: AudioCallback: PBuffer obtained successfully, PBuffer address: 0000000014503F1C
10-09 11:00:45.317 24827 24873 E ZgeAndroid: AudioCallback: Calling MixAndCopyData with PBuffer address: 0000000014503F1C, OnePassSize: 512
10-09 11:00:45.317 24827 24873 E ZgeAndroid: MixAndCopyData: BytesToWrite = 512
10-09 11:00:45.317 24827 24873 E ZgeAndroid: MixAndCopyData: FramesToWrite = 128
10-09 11:00:45.317 24827 24873 E ZgeAndroid: MixAndCopyData: MixBuffer cleared for FramesToWrite = 128
10-09 11:00:45.317 24827 24873 E ZgeAndroid: Platform_EnterMutex: Entering mutex.
10-09 11:00:45.317 24827 24873 E ZgeAndroid: Platform_EnterMutex: Mutex entered successfully.
10-09 11:00:45.317 24827 24873 E ZgeAndroid: MixAndCopyData: Rendering to MixBuffer for FramesToWrite = 128
10-09 11:00:45.317 24827 24873 E ZgeAndroid: RenderToMixBuffer: Entering function
10-09 11:00:45.317 24827 24873 E ZgeAndroid: RenderToMixBuffer: ModulateCrossOvers calculated
10-09 11:00:45.317 24827 24873 E ZgeAndroid: RenderToMixBuffer: ModulateCount = 128, ModulateLeft = 0
10-09 11:00:45.317 24827 24873 E ZgeAndroid: RenderToMixBuffer: Exiting function
10-09 11:00:45.317 24827 24873 E ZgeAndroid: Platform_LeaveMutex: Leaving mutex.
10-09 11:00:45.317 24827 24873 E ZgeAndroid: Platform_LeaveMutex: Mutex left successfully.
10-09 11:00:45.317 24827 24873 E ZgeAndroid: MixAndCopyData: Completed copying to Destination for FramesToWrite = 128
10-09 11:00:45.317 24827 24873 E ZgeAndroid: AudioCallback: ReleasePrimitiveArrayCritical
10-09 11:00:45.317 24827 24873 E ZgeAndroid: AudioCallback: ReleasePrimitiveArrayCritical is OK
10-09 11:00:45.317 24827 24873 E ZgeAndroid: AudioCallback: Is CallNonvirtualIntMethodA working?
10-09 11:00:45.410 24827 24874 E ZgeAndroid: Platform_LoadModule: Loading module: libGLESv1_CM.so
Now it hangs at
env^.CallNonvirtualIntMethodV(env, track, cAudioTrack, mWrite, C([buffer, 0, OnePassSize]));

I tried to replace it by:
env^.CallNonvirtualIntMethodA(env, track, cAudioTrack, mWrite, C([buffer, 0, OnePassSize]));

But it still hangs there.
Last edited by Ats on Wed Oct 09, 2024 9:01 am, edited 1 time in total.
User avatar
VilleK
Site Admin
Posts: 2357
Joined: Mon Jan 15, 2007 4:50 pm
Location: Stockholm, Sweden
Contact:

Re: Google Play New problem : 64bits

Post by VilleK »

Try this change:

Code: Select all

  Params : array[0..10] of JValue;

  function C(const args : array of const) : JValue;
  var
    I : integer;
  begin
     for I := 0 to High(args) do
       Params[I] := args[I].vtPointer;
     Result := @Params;
  end;
User avatar
Ats
Posts: 768
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: Google Play New problem : 64bits

Post by Ats »

I'm getting errors with this C function:

Code: Select all

var
  Params : array[0..10] of JValue; 

  function C(const args : array of const) : JValue;
  var
    I : integer;
  begin
     for I := 0 to High(args) do
       Params[I] := args[I].vtPointer; // Error: identifier idents no member "vtPointer"
     Result := @Params; // Error: Incompatible types: got "Pointer" expected "jvalue"
  end;
User avatar
VilleK
Site Admin
Posts: 2357
Joined: Mon Jan 15, 2007 4:50 pm
Location: Stockholm, Sweden
Contact:

Re: Google Play New problem : 64bits

Post by VilleK »

Aha, sorry it should be "VPointer" and "PJValue".

I'm impressed with the solutions that ChatGPT suggest for you, they are better than expected.
User avatar
Ats
Posts: 768
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: Google Play New problem : 64bits

Post by Ats »

Now I get:

Code: Select all

  function C(const args : array of const) : PJValue;
  var
    I : integer;
  begin
     for I := 0 to High(args) do
       Params[I] := args[I].VPointer; // Error: Incompatible types: got "Pointer" expected "jvalue"
     Result := @Params;
  end;
The robot suggested handling the cases manually. I had to comment out some of them as it went extra zealous:

Code: Select all

  function C(const args : array of const) : PJValue;
  var
    I : integer;
  begin
     for I := 0 to High(args) do
      begin
        case args[I].VType of
          vtInteger:
            Params[I].i := args[I].VInteger; // Assign integer value
          vtPointer:
            Params[I].l := args[I].VPointer; // Assign pointer value
          //vtBoolean:
          //  Params[I].b := Byte(Ord(args[I].VBoolean)); // Convert Boolean to Byte
          //vtChar:
          //  Params[I].w := Word(args[I].VChar); // Convert Char to Word
          //vtExtended:
          //  Params[I].d := args[I].VExtended^; // Assign double value
          // Add more cases for other types as needed
          else
            raise Exception.Create('Unsupported argument type');
        end;
      end;
     Result := @Params;
  end;
And now the sound is working, and it's not crashing afterward!
We need a bit of a cleanup in C function now :lol:

Edit:
But it's not enough to run Omeganaut yet (with threads disabled).
It's possible that there are still some weird memory leaks, because without audio and threads, Omeganaut works.
But with audio and no threads, I have to delete a few random things like ZGEBullet initialization AND a simple Condition component (return ANDROID;) for the title to show up.
User avatar
VilleK
Site Admin
Posts: 2357
Joined: Mon Jan 15, 2007 4:50 pm
Location: Stockholm, Sweden
Contact:

Re: Google Play New problem : 64bits

Post by VilleK »

Try adding this line as first line in C function:

Fillchar(Params, SizeOf(Params), 0);
Post Reply