0

Using Androidapi.JNI.Media with Delphi 10.2 Tokyo.

I am trying to list the available ringtones and play a different one from current default.

Initialization of JAudioManager and JRingtoneManager seems ok, because I can play the default ringtone.

But when I try to use the RingtoneManager to set Type, or get a Cursor, the program terminates with a system popup which say "The Application (name) was interrupted - restart the app".

procedure TAudioPlayBackForm.Button2Click(Sender: TObject);
var
  AudioObj: JObject;
  AudioMgr: JAudioManager;
  RingtoneMgr: JRingtoneManager; 
  aUri: Jnet_Uri;
  cur: JCursor;
  ringt: JRingtone;
begin
  AudioObj := TAndroidHelper.Activity.getSystemService(TJContext.JavaClass.AUDIO_SERVICE );
  RingtoneMgr := TJRingtoneManager.Wrap((AudioObj as ILocalObject).GetObjectID);
  Log.d('TJRingtoneManager wrap ok');

  aUri := TJRingtoneManager.JavaClass.getActualDefaultRingtoneUri(SharedActivityContext, TJRingtoneManager.JavaClass.TYPE_NOTIFICATION);
  Log.d('getActualDefaultRingtoneUri = '+ JStringToString(aUri.toString) );                                                        

  ringt := TJRingtoneManager.JavaClass.getRingtone(SharedActivityContext, aUri);
  Log.d('getRingtone uri ok = '+ JStringToString( ringt.getTitle(SharedActivityContext) ));

  ringt.play;  // OK !

  RingtoneMgr.setType( 4 );   // <-- CRASH !
  Log.d('RingtoneMgr setType ok');

  cur := RingtoneMgr.getCursor;   // <-- CRASH !
  Log.d('RingtoneMgr getCursor ok = '+ intToStr(cur.getColumnCount));
end;

Any idea? Did I forget to initialize something?

I used this documentation as reference.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Mark
  • 11
  • 4

1 Answers1

2

You're creating the RingtoneManager instance incorrectly. It should be:

// Forget about obtaining AudioObj - it's not relevant
RingtoneMgr := TJRingtoneManager.JavaClass.init(TAndroidHelper.Activity);

This requires the Androidapi.Helpers unit

Dave Nottage
  • 3,411
  • 1
  • 20
  • 57
  • Incidentally, saying that the program has a "crash" isn't terribly useful. Be more specific about what happens, i.e. the *exact* error message(s) if any, and preferably provide a callstack – Dave Nottage Jul 04 '18 at 20:33
  • Thank you very much Dave. Is it necessary to free in some way the RingtoneMgr so initialized ? I ask because after some button clicks (14) no more sound is emitted, but the App still run and produce logcat messages... – Mark Jul 04 '18 at 21:25
  • Do those logcat messages indicate any problems? Since RingtoneMgr is a local reference, and an interface, the reference will automatically be destroyed once the method exits. Same for the others – Dave Nottage Jul 04 '18 at 21:45
  • 1
    @DaveNottage since the `Activity` is passed to the "constructor" (`init()`), it might be holding a reference to the object. So you might need to explicitly `DisposeOf()` it when you are done using it. – Remy Lebeau Jul 05 '18 at 16:12
  • @RemyLebeau I think you mean set the reference to nil. – Dave Nottage Jul 05 '18 at 22:03
  • @DaveNottage No, I meant `DisposeOf()` at the time, but I see now where your confusion is, since interfaces don't have `DisposeOf()`, only objects do. Setting the local reference to `nil` wouldn't clear the reference being held inside of the `Activity` (if such a reference exists, I don't know), in which case, I don't know how to clear that. If there isn't one, then this becomes a non-issue. Maybe the "no more sounds" issue is related to the `Ringtone` itself instead? Or maybe Android just gives up playing ringtones after awhile? – Remy Lebeau Jul 06 '18 at 00:15
  • I solved my problem using a single global instance of RingtoneManager and then change ringtone via Cursor. This way I can play infinite times all melodies (ringtones) available in my Android device. – Mark Jul 06 '18 at 14:03