iOS Tutorial Background playback

This tutorial explains how you can play local audio files or stream audio while your app is in the background.
Standard applications are killed when moved to the background. However you can add the following attribute to your project to mark it as an application that plays audio in the background:
B4X:
#Region  Project Attributes
   #ApplicationLabel: B4i Example
   #Version: 1.0.0
   'Orientation possible values: Portrait, LandscapeLeft, LandscapeRight and PortraitUpsideDown
   #iPhoneOrientations: Portrait, LandscapeLeft, LandscapeRight
   #iPadOrientations: Portrait, LandscapeLeft, LandscapeRight, PortraitUpsideDown
   #Target: iPhone, iPad
   #MinVersion: 8
#End Region
#PlistExtra: <key>UIBackgroundModes</key><array><string>audio</string></array>

Sub Process_Globals
    Public App As Application
    Public NavControl As NavigationController
    Private Page1 As Page
    Private NativeMe As NativeObject
    Private VideoPlayer1 As VideoPlayer
End Sub

Private Sub Application_Start (Nav As NavigationController)
    NativeMe = Me
    NavControl = Nav
    Page1.Initialize("Page1")
    Page1.RootPanel.LoadLayout("1")
    NavControl.ShowPage(Page1)
    NativeMe.RunMethod("setAudioSession", Null)
    VideoPlayer1.LoadVideoUrl("https://stream-dc1.radioparadise.com/mp3-32")
    VideoPlayer1.Play
   
    NativeMe.RunMethod("register", Null)
End Sub

Public Sub ControlEvent (Command As String)
    Select Command
        Case "play"
            VideoPlayer1.Play
        Case "pause"
            VideoPlayer1.Pause
    End Select
End Sub



#If OBJC
@import MediaPlayer;
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>
- (void)setAudioSession {
  AVAudioSession *audioSession = [AVAudioSession sharedInstance];
  NSError *err = nil;
  BOOL success = [audioSession setCategory:AVAudioSessionCategoryPlayback error:&err];
  if (success) {
     success = [audioSession setActive:YES error:&err];
   success = [audioSession setPreferredSampleRate:4096 error:nil];
   [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
  }
  if (!success)
  [NSException raise:@"" format:@"Error setting audio session: %@", err];
}
- (void)register {
   MPRemoteCommandCenter* center = [MPRemoteCommandCenter sharedCommandCenter];
   center.playCommand.enabled = true;
   center.pauseCommand.enabled = true;
   [center.playCommand addTarget:self action:@selector(play)];
   [center.pauseCommand addTarget:self action:@selector(pause)];
}
- (MPRemoteCommandHandlerStatus) play {
   NSLog(@"test");
   [self.bi raiseEvent:nil event:@"controlevent:"  params:@[@"play"]];
   return MPRemoteCommandHandlerStatusSuccess;

}
- (MPRemoteCommandHandlerStatus) pause {
   [self.bi raiseEvent:nil event:@"controlevent:"  params:@[@"pause"]];
   return MPRemoteCommandHandlerStatusSuccess;
}

#end if

The above code will play the radio stream. You can leave your app and the streaming will continue.

With this code the user can play and pause the playback from the draggable control center.
 

Attachments

  • BackgroundPlayback.zip
    3.7 KB · Views: 681
Last edited:

ilan

Expert
Licensed User
Longtime User
this is great... just discovered this thread, did not knew its possible with b4i..
 

yonson

Active Member
Licensed User
Longtime User
brilliant thank you so much for this, really essential for a lot of apps I'm srue
 

susu

Well-Known Member
Licensed User
Longtime User
How can I play online audio source with .m3u file?
 

susu

Well-Known Member
Licensed User
Longtime User
How can I play online audio source with .m3u file?

Sorry, .m3u file works fine for MP3, AAC codec not Ogg Vorbis.
 

Daniel Uribe

Member
Licensed User
Longtime User
Greetings, here the next and previous buttons in background, result very efficient when you have a playlist.

B4X:
Public Sub ControlEvent (Command AsString)
Select Command
         Case"play"
            vv.Play
         Case"pause"
            vv.Pause
        Case "nextTrack"
            Log("next")
        Case "previousTrack"
            Log("previous")
    End Select
End Sub



#If OBJC
@import MediaPlayer;
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>
- (void)setAudioSession {
  AVAudioSession *audioSession = [AVAudioSession sharedInstance];
  NSError *err = nil;
  BOOL success = [audioSession setCategory:AVAudioSessionCategoryPlayback error:&err];
  if (success) {
  success = [audioSession setActive:YES error:&err];
  }
  if (!success)
  [NSException raise:@"" format:@"Error setting audio session: %@", err];
  [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
}
- (void)register {
   MPRemoteCommandCenter* center = [MPRemoteCommandCenter sharedCommandCenter];
   center.playCommand.enabled = true;
   center.pauseCommand.enabled = true;
   center.nextTrackCommand.enabled = true;
   center.previousTrackCommand.enabled = true;
   [center.playCommand addTarget:self action:@selector(play)];
   [center.pauseCommand addTarget:self action:@selector(pause)];
   [center.nextTrackCommand addTarget:self action:@selector(nextTrack)];
   [center.previousTrackCommand addTarget:self action:@selector(previousTrack)];
}
- (void) play {
   NSLog(@"test");
   [self.bi raiseEvent:nil event:@"controlevent:"  params:@[@"play"]];
}
- (void) pause {
   [self.bi raiseEvent:nil event:@"controlevent:"  params:@[@"pause"]];
}
- (void) nextTrack {
   [self.bi raiseEvent:nil event:@"controlevent:"  params:@[@"nextTrack"]];
}
- (void) previousTrack {
   [self.bi raiseEvent:nil event:@"controlevent:"  params:@[@"previousTrack"]];
}
- (void)remoteControlReceivedWithEvent:(UIEvent *)receivedEvent {
  if (receivedEvent.type == UIEventTypeRemoteControl) {
     [self.bi raiseEvent:nil event:@"remotecontrol_event:"
       params:@[@(receivedEvent.subtype)]];
   }
}

#end if
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
1. Add this code to the OBJC block:
B4X:
- (MPMediaItemArtwork*)createArtwork:(UIImage*) image {
   return [[MPMediaItemArtwork alloc] initWithBoundsSize:image.size requestHandler:^UIImage* _Nonnull(CGSize aSize) { return image; }];
}
2. Set title and artwork:
B4X:
  Dim artwork As NativeObject = NativeMe.RunMethod("createArtwork:", Array(LoadBitmapResize(File.DirAssets, "b4i_128_128.png", 64, 64, True)))
   SetPlayingInfo(CreateMap("title": "Radio Paradise", "artwork": artwork))
End Sub

Sub SetPlayingInfo (info As Map)
   Dim NowPlayingInfoCenter As NativeObject
   NowPlayingInfoCenter = NowPlayingInfoCenter.Initialize("MPNowPlayingInfoCenter").RunMethod("defaultCenter", Null)
   Dim no As NativeObject = info
   NowPlayingInfoCenter.SetField("nowPlayingInfo", no.RunMethod("ToDictionary", Null))
End Sub
 

cloner7801

Active Member
Licensed User
Longtime User
1. Add this code to the OBJC block:
B4X:
- (MPMediaItemArtwork*)createArtwork:(UIImage*) image {
   return [[MPMediaItemArtwork alloc] initWithBoundsSize:image.size requestHandler:^UIImage* _Nonnull(CGSize aSize) { return image; }];
}
2. Set title and artwork:
B4X:
  Dim artwork As NativeObject = NativeMe.RunMethod("createArtwork:", Array(LoadBitmapResize(File.DirAssets, "b4i_128_128.png", 64, 64, True)))
   SetPlayingInfo(CreateMap("title": "Radio Paradise", "artwork": artwork))
End Sub

Sub SetPlayingInfo (info As Map)
   Dim NowPlayingInfoCenter As NativeObject
   NowPlayingInfoCenter = NowPlayingInfoCenter.Initialize("MPNowPlayingInfoCenter").RunMethod("defaultCenter", Null)
   Dim no As NativeObject = info
   NowPlayingInfoCenter.SetField("nowPlayingInfo", no.RunMethod("ToDictionary", Null))
End Sub
How can I set playing info ? with SetPlayingInfo

can you post a example?
---
SOLVED !
 
Last edited:
Top