[Android]BASS
Moderator: 2ffat
Re: [Android]BASS
Thank You!
Is it my steps correctly?
1. I create a service in it code with the launch of audio.
2. And in the application, send broadcast messages about the start or stop of playback.
I have never used broadcast. Do I need to use Indy to send broadcast message? Can you show me an example of how to send broadcast message in my case? If possible in Pascal because I have to create an application Android 64 bit.
Is it my steps correctly?
1. I create a service in it code with the launch of audio.
2. And in the application, send broadcast messages about the start or stop of playback.
I have never used broadcast. Do I need to use Indy to send broadcast message? Can you show me an example of how to send broadcast message in my case? If possible in Pascal because I have to create an application Android 64 bit.
Re: [Android]BASS
I am not an Android developer, so this is WAY outside my area of expertise.
Unless you want other apps to control your service, using broadcast messages is not the best way to communicate between your UI and service. A Binding makes more sense, as it is a direct line of communication. See Embarcadero's TLocalServiceConnection and TRemoteServiceConnection classes, which have a BindService() method.
Creating Android Services
No. Indy deals with network communications, not inter-process messaging.
Remy Lebeau (TeamB)
Lebeau Software
Lebeau Software
Re: [Android]BASS
Thank you.
Are my first steps in creating a service correct?
Are my first steps in creating a service correct?
Code: Select all
unit UnitSrvice;
interface
uses
System.SysUtils,
System.Classes,
System.Android.Service,
AndroidApi.JNI.GraphicsContentViewText,
Androidapi.JNI.Os, bass;
type
TDM = class(TAndroidService)
function AndroidServiceStartCommand(const Sender: TObject;
const Intent: JIntent; Flags, StartId: Integer): Integer;
function AndroidServiceBind(const Sender: TObject;
const AnIntent: JIntent): JIBinder;
function AndroidServiceUnBind(const Sender: TObject;
const AnIntent: JIntent): Boolean;
private
{ Private declarations }
public
{ Public declarations }
end;
var
DM: TDM;
str: HSTREAM;
implementation
{%CLASSGROUP 'FMX.Controls.TControl'}
{$R *.dfm}
uses
Androidapi.JNI.App;
function TDM.AndroidServiceBind(const Sender: TObject;
const AnIntent: JIntent): JIBinder;
begin
BASS_Init(-1, 44100, 0, nil, nil); //Maybe this line of code in OnCreate AndroidService?
BASS_StreamFree(str);
str := BASS_StreamCreateURL(PChar('http://91.199.194.34:8000'), 0, BASS_UNICODE, nil, nil);
//ShowMessage(IntToStr(BASS_ErrorGetCode));
If BASS_ErrorGetCode = 0 Then
Begin
BASS_ChannelPlay(str, True); //start play
End;
Result := GetBinder;
end;
function TDM.AndroidServiceStartCommand(const Sender: TObject;
const Intent: JIntent; Flags, StartId: Integer): Integer;
begin
Result := TJService.JavaClass.START_STICKY;
end;
function TDM.AndroidServiceUnBind(const Sender: TObject;
const AnIntent: JIntent): Boolean;
begin
BASS_ChannelStop(str); //stop play
BASS_StreamFree(str);
JavaService.StopService(AnIntent);
Result := False;
end;
end.
Re: [Android]BASS
My host app:
In AndroidManifest.template.xml add:
<service android:exported="true" android:name="com.embarcadero.services.ServicPablicRadio" />
But the music still stops playing if you minimize the application.
Code: Select all
unit UnitMain;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
System.Android.Service, FMX.Controls.Presentation, FMX.StdCtrls;
type
TForm1 = class(TForm)
ButtonPlay: TButton;
ButtonStop: TButton;
procedure ButtonPlayClick(Sender: TObject);
procedure ButtonStopClick(Sender: TObject);
private
{ Private declarations }
FService: TLocalServiceConnection;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
procedure TForm1.ButtonPlayClick(Sender: TObject);
begin
if FService = Nil Then Begin
FService := TLocalServiceConnection.Create;
FService.StartService('ServicPablicRadio');
end;
FService.BindService('ServicPablicRadio', 0);
end;
procedure TForm1.ButtonStopClick(Sender: TObject);
begin
if FService <> Nil then begin
FService.UnbindService;
FService := Nil;
end;
end;
end.
<service android:exported="true" android:name="com.embarcadero.services.ServicPablicRadio" />
But the music still stops playing if you minimize the application.

Re: [Android]BASS
Again, I direct you to the Android documentation, which discusses this in detail:
Media app architecture overview
Audio app overview
The key is to write a service that implements MediaBrowserService and contains a MediaSession, and write a UI app that contains a MediaBrowser and MediaController to communicate with the service.
This is the way Android prefers an audio app be written. How you translate that into Delphi, I don't know. I'm sure it will involve using Embarcadero's JNIBridge framework to access these Android classes, if Embarcadero hasn't already imported them into its Androidapi namespace.
Remy Lebeau (TeamB)
Lebeau Software
Lebeau Software
Re: [Android]BASS
Thanks for the additional information!
I think the error is also in RAD 10.3.3
1. I create new an Android service 64 bit.
2. I create new app 64 bit.
3. Not use bass.
4. Use this short video: https://www.youtube.com/watch?v=0mD3WLK8FYc
Host app:
When I start the application, I see that it is running and the service is running too. Everything works perfectly.
When I overlap the application window with another program, then after two minutes both the application and the service stop.
Or if you remove the application from memory as in a video, then the service also stops.
I don't know why the service stops.
Phone Readmi 5A Android 8.1 MIUI 11.0.2 RAD 10.3.3
I think the error is also in RAD 10.3.3
1. I create new an Android service 64 bit.
2. I create new app 64 bit.
3. Not use bass.
4. Use this short video: https://www.youtube.com/watch?v=0mD3WLK8FYc
Code: Select all
function TDM.AndroidServiceStartCommand(const Sender: TObject;
const Intent: JIntent; Flags, StartId: Integer): Integer;
begin
Result := TJService.JavaClass.START_STICKY;
end;
Code: Select all
System.Android.Service;
private
{ Private declarations }
FService: TLocalServiceConnection;
//-------------------------------------------
procedure TForm1.FormCreate(Sender: TObject);
begin
FService := TLocalServiceConnection.Create;
FService.StartService('serPublic');
end;
When I overlap the application window with another program, then after two minutes both the application and the service stop.
Or if you remove the application from memory as in a video, then the service also stops.
I don't know why the service stops.
Phone Readmi 5A Android 8.1 MIUI 11.0.2 RAD 10.3.3
Re: [Android]BASS
Thank you very much I will investigate!
P.S.
I also found this difficult code. But it does not compile for me. Delphi 10.3.3
Start Foreground service in Delphi 10.3
[DCC Error] Unit1.pas(63): E2003 Undeclared identifier: 'CHANNEL_ID'
[DCC Error] Unit1.pas(97): E2029 ';' expected but 'ELSE' found
[DCC Error] Unit1.pas(130): E2029 '.' expected but ';' found
[DCC Error] Unit1.pas(136): E2003 Undeclared identifier: 'ExtraData'
[DCC Error] Unit1.pas(137): E2003 Undeclared identifier: 'Intent'
[DCC Error] Unit1.pas(137): E2029 'END' expected but ')' found
[DCC Warning] Unit1.pas(138): W1011 Text after final 'END.' - ignored by compiler
What is CHANNEL_ID the author did not explain.
P.S.
I also found this difficult code. But it does not compile for me. Delphi 10.3.3
Start Foreground service in Delphi 10.3
Code: Select all
unit Unit1;
interface
uses
System.SysUtils,
System.Classes,
System.Android.Service,
AndroidApi.JNI.GraphicsContentViewText,
Androidapi.JNI.Os,
Androidapi.JNI.App,
Androidapi.JNI.Support,
Androidapi.JNI.JavaTypes,
Androidapi.Helpers,
Androidapi.JNIBridge;
type
TDM = class(TAndroidService)
function AndroidServiceStartCommand(const Sender: TObject;
const Intent: JIntent; Flags, StartId: Integer): Integer;
private
{ Private declarations }
public
{ Public declarations }
end;
var
DM: TDM;
implementation
{%CLASSGROUP 'FMX.Controls.TControl'}
{$R *.dfm}
function TDM.AndroidServiceStartCommand(const Sender: TObject;
const Intent: JIntent; Flags, StartId: Integer): Integer;
var
ExtraData: String;
{$ifdef VER330}
ServiceChannel: JNotificationChannel;
NotificationManager: JNotificationManager;
Obj: JObject;
{$endif}
NewIntent: JIntent;
ncb: JNotificationCompat_Builder;
ntf: JNotification;
PendingIntent: JPendingIntent;
begin
Result := TJService.JavaClass.START_NOT_STICKY;
// can't ref .O on earlier phones, must hardcode
if TJBuild_VERSION.JavaClass.SDK_INT > 26 then // JBuild_VERSION_CODES.JavaClass.O begin
{$ifdef VER330}
// new ways for SDK > 26 (won't be called when API < 26 anyways)
ServiceChannel := TJNotificationChannel.JavaClass.init(
StringtoJString(CHANNEL_ID),
StrToJCharSequence('My Service Channel'),
TJNotificationManager.JavaClass.IMPORTANCE_DEFAULT
);
Obj := TAndroidHelper.Context.getSystemService(
TJContext.JavaClass.NOTIFICATION_SERVICE);
NotificationManager := TJNotificationManager.Wrap(Obj);
NotificationManager.createNotificationChannel(ServiceChannel);
NewIntent:= TAndroidHelper.Context.getPackageManager().getLaunchIntentForPackage(
TAndroidHelper.Context.getPackageName());
NewIntent.setAction(TJIntent.JavaClass.ACTION_MAIN);
NewIntent.addCategory(TJIntent.JavaClass.CATEGORY_LAUNCHER);
NewIntent.addFlags(TJIntent.JavaClass.FLAG_ACTIVITY_NEW_TASK);
PendingIntent := TJPendingIntent.JavaClass.getActivity(
TAndroidHelper.Context, 0, NewIntent,
TJIntent.JavaClass.FLAG_ACTIVITY_NEW_TASK
);
ncb := TJNotificationCompat_Builder.JavaClass.init(
TAndroidHelper.Context,
StringToJString(CHANNEL_ID)
);
ncb.setContentTitle(StrToJCharSequence('MyService'));
// ncb.setTicker(StrToJCharSequence('MyCommsService')); // can't remember why this is commented out to be honest
ncb.setSmallIcon(JavaService.getApplicationInfo.icon);
ncb.setContentIntent(PendingIntent);
ncb.setOngoing(True);
ntf := ncb.build;
{$endif VER330}
end
else
begin
{$ifdef ORDINARY_NOTIFICATION}
PendingIntent := TJPendingIntent.JavaClass.getActivity(
JavaService.getApplicationContext, 0, Intent, 0
);
ntf := TJNotification.Create;
ntf.icon := JavaService.getApplicationInfo.icon;
ntf.setLatestEventInfo(
JavaService.getApplicationContext,
StrToJCharSequence('MyService'),
StrToJCharSequence('MyCommsService'), PendingIntent);
{$endif}
{$ifdef CLICKABLE_NOTIFICATION}
NewIntent:= TAndroidHelper.Context.getPackageManager().getLaunchIntentForPackage(
TAndroidHelper.Context.getPackageName());
NewIntent.setAction(TJIntent.JavaClass.ACTION_MAIN);
NewIntent.addCategory(TJIntent.JavaClass.CATEGORY_LAUNCHER);
NewIntent.addFlags(TJIntent.JavaClass.FLAG_ACTIVITY_NEW_TASK);
PendingIntent := TJPendingIntent.JavaClass.getActivity(
TAndroidHelper.Context, 0, NewIntent,
TJIntent.JavaClass.FLAG_ACTIVITY_NEW_TASK
);
ncb := TJNotificationCompat_Builder.JavaClass.init(TAndroidHelper.Context);
ncb.setContentTitle(StrToJCharSequence('MyService'));
ncb.setTicker(StrToJCharSequence('MyCommsService'));
ncb.setSmallIcon(JavaService.getApplicationInfo.icon);
ncb.setContentIntent(PendingIntent);
ncb.setOngoing(True);
ntf := ncb.build;
{$endif}
end;
JavaService.startForeground(StartId, ntf);
if Intent <> nil then
begin
ExtraData := TAndroidHelper.JStringToString(
Intent.getStringExtra(TAndroidHelper.StringToJString('ExtraData')));
end;
end;
end.
[DCC Error] Unit1.pas(97): E2029 ';' expected but 'ELSE' found
[DCC Error] Unit1.pas(130): E2029 '.' expected but ';' found
[DCC Error] Unit1.pas(136): E2003 Undeclared identifier: 'ExtraData'
[DCC Error] Unit1.pas(137): E2003 Undeclared identifier: 'Intent'
[DCC Error] Unit1.pas(137): E2029 'END' expected but ')' found
[DCC Warning] Unit1.pas(138): W1011 Text after final 'END.' - ignored by compiler
What is CHANNEL_ID the author did not explain.
Re: [Android]BASS
Since that 'begin' follows a comment, it should be on the next line:Lena wrote: ↑Tue Oct 20, 2020 2:42 amCode: Select all
// can't ref .O on earlier phones, must hardcode if TJBuild_VERSION.JavaClass.SDK_INT > 26 then // JBuild_VERSION_CODES.JavaClass.O begin {$ifdef VER330}
Code: Select all
// can't ref .O on earlier phones, must hardcode
if TJBuild_VERSION.JavaClass.SDK_INT > 26 then // JBuild_VERSION_CODES.JavaClass.O
begin
{$ifdef VER330}
Use whatever string value you want. The documentation for the NotificationChannel constructor says:
The id of the channel. Must be unique per package. The value may be truncated if it is too long.
I think those are just side-effects of the earlier errors.Lena wrote: ↑Tue Oct 20, 2020 2:42 am [DCC Error] Unit1.pas(97): E2029 ';' expected but 'ELSE' found
[DCC Error] Unit1.pas(130): E2029 '.' expected but ';' found
[DCC Error] Unit1.pas(136): E2003 Undeclared identifier: 'ExtraData'
[DCC Error] Unit1.pas(137): E2003 Undeclared identifier: 'Intent'
[DCC Error] Unit1.pas(137): E2029 'END' expected but ')' found
[DCC Warning] Unit1.pas(138): W1011 Text after final 'END.' - ignored by compiler
It is just a unique ID that you create to refer to your channel. See https://developer.android.com/training/notify-user/channels.
Remy Lebeau (TeamB)
Lebeau Software
Lebeau Software
Re: [Android]BASS
Thank You rlebeau!
Now Buil OK.
2. Set Options app Uses Permissions -> Foreground service=true in service app.
3. Created a test application and service with the code above. It started. An application icon appeared in the notification bar at the top of the phone screen. Minimize the application from the screen and lock the screen. In about 20 minutes we wake up the phone. The application icon has not disappeared.
It looks like it works...
Now Buil OK.
Code: Select all
uses
System.SysUtils,
System.Classes,
System.Android.Service,
AndroidApi.JNI.GraphicsContentViewText,
Androidapi.JNI.Os,
Androidapi.JNI.App,
Androidapi.JNI.Support,
Androidapi.JNI.JavaTypes,
Androidapi.Helpers,
Androidapi.JNIBridge,
Androidapi.Jni;
type
TDM = class(TAndroidService)
function AndroidServiceStartCommand(const Sender: TObject;
const Intent: JIntent; Flags, StartId: Integer): Integer;
private
{ Private declarations }
public
{ Public declarations }
end;
var
DM: TDM;
implementation
{%CLASSGROUP 'FMX.Controls.TControl'}
{$R *.dfm}
function TDM.AndroidServiceStartCommand(const Sender: TObject;
const Intent: JIntent; Flags, StartId: Integer): Integer;
var
ExtraData: String;
{$ifdef VER330}
ServiceChannel: JNotificationChannel;
NotificationManager: JNotificationManager;
Obj: JObject;
{$endif}
NewIntent: JIntent;
ncb: JNotificationCompat_Builder;
ntf: JNotification;
PendingIntent: JPendingIntent;
begin
Result := TJService.JavaClass.START_NOT_STICKY;
// can't ref .O on earlier phones, must hardcode
if TJBuild_VERSION.JavaClass.SDK_INT > 26 then // JBuild_VERSION_CODES.JavaClass.O
begin
{$ifdef VER330}
// new ways for SDK > 26 (won't be called when API < 26 anyways)
ServiceChannel := TJNotificationChannel.JavaClass.init(
StringtoJString('com.radio.one'), //CHANNEL_ID
StrToJCharSequence('Public radio Channel'),
TJNotificationManager.JavaClass.IMPORTANCE_DEFAULT
);
Obj := TAndroidHelper.Context.getSystemService(
TJContext.JavaClass.NOTIFICATION_SERVICE);
NotificationManager := TJNotificationManager.Wrap(Obj);
NotificationManager.createNotificationChannel(ServiceChannel);
NewIntent:= TAndroidHelper.Context.getPackageManager().getLaunchIntentForPackage(
TAndroidHelper.Context.getPackageName());
NewIntent.setAction(TJIntent.JavaClass.ACTION_MAIN);
NewIntent.addCategory(TJIntent.JavaClass.CATEGORY_LAUNCHER);
NewIntent.addFlags(TJIntent.JavaClass.FLAG_ACTIVITY_NEW_TASK);
PendingIntent := TJPendingIntent.JavaClass.getActivity(
TAndroidHelper.Context, 0, NewIntent,
TJIntent.JavaClass.FLAG_ACTIVITY_NEW_TASK
);
ncb := TJNotificationCompat_Builder.JavaClass.init(
TAndroidHelper.Context,
StringToJString('com.radio.one')
);
ncb.setContentTitle(StrToJCharSequence('PublicRadio'));
// ncb.setTicker(StrToJCharSequence('MyCommsService')); // can't remember why this is commented out to be honest
ncb.setSmallIcon(JavaService.getApplicationInfo.icon);
ncb.setContentIntent(PendingIntent);
ncb.setOngoing(True);
ntf := ncb.build;
{$endif VER330}
end
else
begin
{$ifdef ORDINARY_NOTIFICATION}
PendingIntent := TJPendingIntent.JavaClass.getActivity(
JavaService.getApplicationContext, 0, Intent, 0
);
ntf := TJNotification.Create;
ntf.icon := JavaService.getApplicationInfo.icon;
ntf.setLatestEventInfo(
JavaService.getApplicationContext,
StrToJCharSequence('PublicRadio'),
StrToJCharSequence('PublicRadioService'), PendingIntent); //MyCommsService
{$endif}
{$ifdef CLICKABLE_NOTIFICATION}
NewIntent:= TAndroidHelper.Context.getPackageManager().getLaunchIntentForPackage(
TAndroidHelper.Context.getPackageName());
NewIntent.setAction(TJIntent.JavaClass.ACTION_MAIN);
NewIntent.addCategory(TJIntent.JavaClass.CATEGORY_LAUNCHER);
NewIntent.addFlags(TJIntent.JavaClass.FLAG_ACTIVITY_NEW_TASK);
PendingIntent := TJPendingIntent.JavaClass.getActivity(
TAndroidHelper.Context, 0, NewIntent,
TJIntent.JavaClass.FLAG_ACTIVITY_NEW_TASK
);
ncb := TJNotificationCompat_Builder.JavaClass.init(TAndroidHelper.Context);
ncb.setContentTitle(StrToJCharSequence('PublicRadio'));
ncb.setTicker(StrToJCharSequence('PublicRadioService')); //MyCommsService
ncb.setSmallIcon(JavaService.getApplicationInfo.icon);
ncb.setContentIntent(PendingIntent);
ncb.setOngoing(True);
ntf := ncb.build;
{$endif}
end;
JavaService.startForeground(StartId, ntf);
if Intent <> nil then
begin
ExtraData := TAndroidHelper.JStringToString(
Intent.getStringExtra(TAndroidHelper.StringToJString('ExtraData')));
end;
end;
end.
3. Created a test application and service with the code above. It started. An application icon appeared in the notification bar at the top of the phone screen. Minimize the application from the screen and lock the screen. In about 20 minutes we wake up the phone. The application icon has not disappeared.
It looks like it works...

Re: [Android]BASS
Next step:
Added a service to a project with BASS. Everything works as it should. For an hour now, the music has been playing when the application is minimized and the screen is locked.
Added a service to a project with BASS. Everything works as it should. For an hour now, the music has been playing when the application is minimized and the screen is locked.
Re: [Android]BASS
I use this code to close the application and stop the service:
MainActivity.finish;
It works.
Do I need any additional steps to stop the service?
MainActivity.finish;
It works.
Do I need any additional steps to stop the service?
Re: [Android]BASS
Hi.
Not all phones start the service. Everything is fine on my Android 8.1. I took a phone with Android 7. The service does not start. There is no service icon in the tray. Maybe need to add something to the service code?
If someone has a phone with Android 9, please check or the service starts there. Direct link to apk file:
http://nsnllc.um.la/PublicRadio1.apk
Thanks.
P.S.
Android 10 will not work as a bug:
https://quality.embarcadero.com/browse/RSP-27218
RAD 10.3.3 SDK 29 but there is an error in the manifest still android:targetSdkVersion="28"
Not all phones start the service. Everything is fine on my Android 8.1. I took a phone with Android 7. The service does not start. There is no service icon in the tray. Maybe need to add something to the service code?
If someone has a phone with Android 9, please check or the service starts there. Direct link to apk file:
http://nsnllc.um.la/PublicRadio1.apk
Thanks.
P.S.
Android 10 will not work as a bug:
https://quality.embarcadero.com/browse/RSP-27218
RAD 10.3.3 SDK 29 but there is an error in the manifest still android:targetSdkVersion="28"
Re: [Android]BASS
I am trying to use now 10.4.1
Debugger still doesn't work.
The application starts normally but the service does not start.
In manifest:
<uses-sdk android:minSdkVersion="23" android:targetSdkVersion="29" />
<service android:exported="false" android:name="com.embarcadero.services.serPublic" />
Somewhere there is an mistake in the service code...
Debugger still doesn't work.
The application starts normally but the service does not start.

In manifest:
<uses-sdk android:minSdkVersion="23" android:targetSdkVersion="29" />
<service android:exported="false" android:name="com.embarcadero.services.serPublic" />
Somewhere there is an mistake in the service code...
Code: Select all
//start service
procedure TForm1.FormCreate(Sender: TObject);
Begin
if not BASS_Init(-1, 44100, 0, nil, nil) Then Begin
ShowMessage('Failed to initialize audio!' + sLineBreak + 'Не удалось инициализировать audio!');
Exit;
end;
if FService = Nil Then Begin
FService := TLocalServiceConnection.Create;
FService.StartService('serPublic');
ShowMessage('StartService'); // OK!
end;
End
Re: [Android]BASS
It is necessary to re-set the foreground service permission in the project options.
I can see in the running applications that the service is running. However, there is no service icon in the tray. In 10.3.3, the service icon was in the tray.
I can see in the running applications that the service is running. However, there is no service icon in the tray. In 10.3.3, the service icon was in the tray.
