Перейти к содержанию
Fire Monkey от А до Я
  • 0

[Android] Воспроизводить аудио


Ingalime

Вопрос

Подскажите, пожалуйста, можно ли воспроизводить аудио поток в FMX, если известен статический адрес и порт -> IP:порт?

Спасибо.

Изменено пользователем Ingalime
Ссылка на комментарий
  • Ответы 82
  • Создана
  • Последний ответ

Лучшие авторы в вопросе

Рекомендуемые сообщения

  • 0

При создании такого сервиса какой наиболее правильный вариант выбрать? Intent Local, Intent Remote? Сервис как и приложение должно быть Андроид 64?

Хотелось бы как у правильных плееров, при свернутом приложении или блокированном экране - музыка играла. При выгруженном пользователем приложения из памяти, музыка прекращала воспроизведение.

P.S.

А вообще выяснилось, что и пустая служба без музыки у меня убивается. В чем причина не понятно:

http://fire-monkey.ru/topic/6863-android-services/#comment-39981

 

int.JPG

Изменено пользователем Ingalime
Ссылка на комментарий
  • 0

Я прощу прощения, я не до конца понимаю...

Мною создан плеер интернет радио который читает поток с нужного мне url адреса. Все работает как надо. Взяты нужные SO файлы с сайта BASS. Песни играют, вижу название этих песен. Все как говориться - картина маслом. Приложение полностью отвечает поставленной задаче.

Осталось только заставить приложение работать если пользователь заблокировал экран телефона или свернул приложение. В этом случае Андроид прибивает приложение минуты через две. Для музыкального плеера это не подходит.

Необходима служба Foreground. Тут, и в сети предложено много вариантов чего попробовать. Я уже запуталась...

Тут есть пример: 

Start Foreground service in Delphi 10.3

и тут, тот же автор на китайском сайте приводит этот же код (внизу страницы):

https://mlog.club/article/3507628

Вот мои uses для этого примера.

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;

Нет у меня понимания Java. Ибо чтобы откомпилировать этот код, надо понимать, например, что такое CHANNEL_ID в его коде?

Вопрос такой: какой же все же окончательно правильный путь для много-мучительного музыкального плеера в Дельфи 10.3.3, чтобы было как у плееров из маркета без проблем - музыка в фоне? :)

Изменено пользователем Ingalime
Ссылка на комментарий
  • 0

Ну так вы смотрите сразу справку гуугл

CHANNEL_ID -

The id of the channel. Must be unique per package. The value may be truncated if it is too long.

Идентификатор канала. Должно быть уникальным для каждого пакета. Значение может быть усечено, если оно слишком длинное.

Допустим пусть это будет имя пакета + '_id_1'

Смысл в том что приложение может создать несколько уведомлений, и что если вам нужно удалить уведомление вы 

NotificationManager notificationManager =
        (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// The id of the channel.
String id = имя пакета + '_id_1';
notificationManager.deleteNotificationChannel(id);
Ссылка на комментарий
  • 0

Теперь Build нормально проходит.

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.

Потом иду у этой службы в Uses Permissions и ставлю Foreground service=true. Верно?

Почему-то не сразу удалось поставить Foreground service=true ругалось, что не верный Version Code. Но все же установилась галочка  Foreground service=true.

А теперь, что у приложения вызывающего службу просто написать так?

private
    { Private declarations }
    FService: TLocalServiceConnection;

//--------------------------------------------
procedure TForm1.Button1Click(Sender: TObject);
begin
  if FService = Nil Then Begin

  FService := TLocalServiceConnection.Create;
  FService.StartService('serPublic');//имя службы libserPublic.so
  end;

end;

Все ли правильно и возможно какие шаги упущены?

Ссылка на комментарий
  • 0

Создано тест приложение и сервис с кодом выше. Запустилось. Появился в шторке значок приложения. Свертываем приложение с экрана и блокируем экран. Минут через 20 будим телефон. Значок в шторке на месте. Похоже работает...

P.S.

Просьба кто знает java и имеет время, "разбавить" код сервиса подробными комментариями, а то не совсем понятно что там и как. Спасибо.

Изменено пользователем Ingalime
Ссылка на комментарий
  • 0
28 минут назад, Ingalime сказал:

Создано тест приложение и сервис с кодом выше. Запустилось. Появился в шторке значок приложения. Свертываем приложение с экрана и блокируем экран. Минут через 20 будим телефон. Значок в шторке на месте. Похоже работает...

P.S.

Просьба кто знает java и имеет время, "разбавить" код сервиса подробными комментариями, а то не совсем понятно что там и как. Спасибо.

Что значит "разбавить код сервиса комментариями"? Там же все и так на Delphi. Или имеется в виду, паралельно delphi написать в комментарии тот же код на Java?

Ссылка на комментарий
  • 0
12 минут назад, Ingalime сказал:

Просто добавить комментарии к строкам. Например зачем там

ExtraData := TAndroidHelper.JStringToString

и т.д.

А, ок, понял. Но сейчас уже ухожу с работы от компа... Если никто не распишет, может, на выходных, или уже в понедельник, распишу.

Да, и код сервиса "выдран" от куда то, я б, честно, его поменял немного, но ничего.

По поводу ExtraData - при запуске сервиса предполагается какое-то дальнейшее действие, вот оно в эту дату и прилетает при запуске, и дальше автор что-то с этим значением делает

Ссылка на комментарий
  • 0
3 минуты назад, mazayhin сказал:

Да, и код сервиса "выдран" от куда то, я б, честно, его поменял немного, но ничего.

Было бы замечательно иметь нормальный  Foreground service. Многим бы пригодился.

Ссылка на комментарий
  • 0

Добавила сервис в проект с BASS. Все работает как надо. Уже час музыка играет при свернутом приложении и заблокированном экране. ✌️

P.S.

А как можно службу остановить?

Изменено пользователем Ingalime
Ссылка на комментарий
  • 0
1 час назад, Ingalime сказал:

Добавила сервис в проект с BASS. Все работает как надо. Уже час музыка играет при свернутом приложении и заблокированном экране. ✌️

P.S.

А как можно службу остановить?

Вот я и говорил что не плохо было бы исправить этот код, и в extra отправлять комманды сервису из приложения, например, пауза там, и останавливать так же, посылая интент из приложения

Ссылка на комментарий
  • 0
 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'));
   // Текст для служб специальных возможностей
  //  Начиная с выпуска L, этот текст больше не отображается на экране, но он по-прежнему полезен для служб специальных возможностей (где он служит звуковым объявлением о появлении уведомления).                                                     
   // 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;

Как то так

Изменено пользователем OnePeople
Ссылка на комментарий
  • 0
34 минут назад, OnePeople сказал:

 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'));
   // Текст для служб специальных возможностей
  //  Начиная с выпуска L, этот текст больше не отображается на экране, но он по-прежнему полезен для служб специальных возможностей (где он служит звуковым объявлением о появлении уведомления).                                                     
   // 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;

Как то так

Сибирь рулит )) 

Ссылка на комментарий
  • 0

Спасибо.

Код: MainActivity.finish;

Закрывает приложение и выгружает сервис. Все как положено. А не надо ли каких-то дополнительных действий для закрытия и остановки сервиса или этой строки кода достаточно?

Ссылка на комментарий
  • 0

Проблемка. На Андроид 8.1 все нормально. Запускается приложение и значок службы вверху присутствует. На Андроид 7 служба не запускается и не работает. Андроид останавливает приложение через пару минут при заблокированном экране на телефоне с Андроид 7. Подскажите куда смотреть? Может кто посмотрит на своем телефоне, может и на других версиях служба не работает... Ссылка на apk: PublicRadio

Спасибо.

//запуск службы
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');
  end;

End;

 

Изменено пользователем Ingalime
Ссылка на комментарий
  • 0

После компиляции проекта в 10.4.1 служба перестала запускаться, хотя сам проект запускается без проблем и работает. Дебаггер с моим телефоном Readme 5A Андроид 8.1 не работает.

Нет значка службы вверху в трее.

Может кто из специалистов глянет и поправит код службы чтобы запускалась...

1. Тут проект. Прошу прощения за размер. SO файлы большие. Скачать: BASS плеер

2. Папка delphi82 копируется сюда: C:\Users\Lena\Documents\Embarcadero\Studio\Projects

Соответственно пути в опциях проекта для BASS:

C:\Users\Lena\Documents\Embarcadero\Studio\Projects\delphi82\bass-android-test\arm64-v8a;

C:\Users\Lena\Documents\Embarcadero\Studio\Projects\delphi82\bass-android-test\armeabi;

C:\Users\Lena\Documents\Embarcadero\Studio\Projects\delphi82\bass-android-test\armeabi-v7a

3. Открыть ProjectGroupPublicRadio.groupproj  Run PublicRadio

Спасибо.

Изменено пользователем Ingalime
Ссылка на комментарий
  • 0

Слетела галочка в разрешениях в опциях проекта foreground service. Однако установка ее не помогла - нет значка службы в трее...

P.S.

Странно значка нет, а в запущенных приложениях служба есть. В 10.3.3 был значок в трее...

Изменено пользователем Ingalime
Ссылка на комментарий
  • 0

Короче не работает. Служба стартует, но она не foreground. Если свернуть приложение, служба перестает работать через пару минут.

Предложенное выше решение устарело и не подходит т.к. оно работает для sdk 28. Гугл маркет требует с августа sdk 29.

Таким образом как создать простую foreground службу в 10.4.1 остаётся не решенным вопросом.

Изменено пользователем Ingalime
Ссылка на комментарий
  • 0

Спасибо. Подскажите как правильно добавить третий параметр в код запуска службы?

JavaService.startForeground(StartId,  ntf,  2);//too many actual parametrs

В выпадающем списке нет варианта с тремя параметрами. Рис.

В манифесте <uses-sdk android:minSdkVersion="23" android:targetSdkVersion="29" />

 

serv.jpg

Ссылка на комментарий
  • 0

Я так поняла что в  Androidapi.JNI.App надо метод переписать так:

 procedure startForeground(id: Integer; notification: JNotification; foregroundServiceType: Integer); cdecl;

А какие следующие шаги чтобы код службы увидел это обновление? Спасибо.

Ссылка на комментарий
  • 0
В 25.11.2020 в 18:52, Ingalime сказал:

Я так поняла что в  Androidapi.JNI.App надо метод переписать так:


 procedure startForeground(id: Integer; notification: JNotification; foregroundServiceType: Integer); cdecl;

А какие следующие шаги чтобы код службы увидел это обновление? Спасибо.

Не подскажете, как сделать, чтобы во время воспроизведения радио потока, при поступающем звонке по телефону отключалось радио? А после разговора автоматически включалось?

Заметил такую особенность, что на Андроиде 7 отключается, даже делать ничего не надо. А на Андроиде 9 так не происходит - радио играет, невозможно по телефону разговаривать, пока вручную не отключишь радио. 

Может кто подскажет? 

Делфи 10.3.3.

Ссылка на комментарий

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу

×
×
  • Создать...