I'm trying to get context in service. I know that Service extends Context and I can get it at onCreate method. So I tried it and got error. I don't understand other example uses the context at onCreate and works, but not to me. Also I registered my service. the error is occurred at this line in service.
player = ExoPlayerFactory.newSimpleInstance(mContext, DefaultTrackSelector())
Why the context is null even though I initialized the context in onCreate? I saw the similar problem at here Android getContext on a background Service
error
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Context android.content.Context.getApplicationContext()' on a null object reference
activity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val musicPlayer = binding.musicPlayer
musicPlayer.player = audioService.getplayerInstance()
musicPlayer.player.playWhenReady = true
mIntent = Intent(this,AudioService::class.java)
Util.startForegroundService(this,mIntent)
bindService(mIntent, mConnection, Context.BIND_AUTO_CREATE);
initializePlayer();
}
Service
class AudioService : Service() {
private val mBinder: IBinder =Binder()
private var player: SimpleExoPlayer? = null
private var playerNotificationManager: PlayerNotificationManager? = null
private var cacheDataSourceFactory : CacheDataSourceFactory?=null
var mContext: Context? = null
override fun onDestroy() {
releasePlayer()
super.onDestroy()
}
override fun onCreate() {
super.onCreate()
mContext = this
if (player == null) {
startPlayer()
}
}
private fun releasePlayer() {
if (player != null) {
playerNotificationManager!!.setPlayer(null)
player!!.release()
player = null
}
}
override fun onBind(intent: Intent?): IBinder {
return mBinder
}
fun getplayerInstance(): SimpleExoPlayer? {
if (player == null) {
startPlayer()
}
return player
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
return START_STICKY
}
private fun startPlayer() {
val uri: Uri = Uri.parse("https://storage.googleapis.com/exoplayer-test-media-0/Jazz_In_Paris.mp3")
player = ExoPlayerFactory.newSimpleInstance(mContext, DefaultTrackSelector())
cacheDataSourceFactory = getCacheDataSourceFactory(mContext!!)
val mediaSource: MediaSource = ProgressiveMediaSource.Factory(cacheDataSourceFactory)
.createMediaSource(uri)
player!!.prepare(mediaSource)
player!!.setPlayWhenReady(true)
playerNotificationManager = PlayerNotificationManager.createWithNotificationChannel(
mContext,"channel_id", com.haii.exoplayerdemo.R.string.channelName,com.haii.exoplayerdemo.R.string.channelDescription,11,
object : PlayerNotificationManager.MediaDescriptionAdapter{
override fun createCurrentContentIntent(player: Player): PendingIntent? {
val intent = Intent(mContext,MainActivity::class.java)
return PendingIntent.getActivity(mContext,0,intent,PendingIntent.FLAG_UPDATE_CURRENT)
}
override fun getCurrentContentText(player: Player): String? {
return "description"
}
override fun getCurrentContentTitle(player: Player): String {
return "title"
}
override fun getCurrentLargeIcon(
player: Player,
callback: PlayerNotificationManager.BitmapCallback
): Bitmap? {
return null
}
} ,
object : PlayerNotificationManager.NotificationListener {
override fun onNotificationStarted(notificationId: Int, notification: Notification) {
Log.d("TAG","onNotificationStarted")
startForeground(notificationId,notification)
}
override fun onNotificationPosted(notificationId: Int, notification: Notification, ongoing: Boolean) {
Log.d("TAG","onNotificationPosted")
// startForeground(notificationId,notification)
}
override fun onNotificationCancelled(notificationId: Int, dismissedByUser: Boolean) {
Log.e("TAG","onNotificationCancelled 2")
stopSelf()
}
override fun onNotificationCancelled(notificationId: Int) {
Log.e("TAG","onNotificationCancelled 1")
// stopSelf()
}
}
)
playerNotificationManager!!.setPlayer(player)
}
fun getCacheDataSourceFactory(context : Context) : com.haii.exoplayerdemo.CacheDataSourceFactory?{
if(cacheDataSourceFactory==null){
cacheDataSourceFactory = com.haii.exoplayerdemo.CacheDataSourceFactory(
context,
DefaultDataSourceFactory(context, "ua"),
MyExoPlayer.MAX_CACHE_VALUE, MyExoPlayer.MAX_CACHE_FILE_VALUE
)
}
return cacheDataSourceFactory
}
}
I`m refering from here https://developer.android.com/guide/components/services.
The thing that you are doing wrong is calling getPlayerInstance() before onCreate is called. Your oncreate is called when you either bind or start the service. Good luck
Related
I am a noob in Kotlin.
I've made a streaming music player using Exoplayer2.
For running this music player in background, I tried to bind activity to service.
But it is not working.
I dont know why this player is stopped outside the app even though i add the foreground service.
Can anybody help me? :(
MusicService.kt
var mExoPlayer: SimpleExoPlayer? = null
class MusicService : MediaBrowserServiceCompat() {
private var mMediaSession: MediaSessionCompat? = null
private lateinit var mStateBuilder: PlaybackStateCompat.Builder
private var playbackPosition = 0L
private var currentWindow = 0
private var oldUri: Uri? = null
private val mMediaSessionCallback = object : MediaSessionCompat.Callback() {
override fun onPlayFromUri(uri: Uri?, extras: Bundle?) {
super.onPlayFromUri(uri, extras)
uri?.let {
val mediaSource = extractMediaSourceFromUri(uri)
if (uri != oldUri)
play(mediaSource)
else play()
oldUri = uri
}
}
override fun onPause() {
super.onPause()
pause()
}
override fun onStop() {
super.onStop()
stop()
}
}
override fun onCreate() {
super.onCreate()
initializePlayer()
initializeExtractor()
initializeAttributes()
mMediaSession = MediaSessionCompat(baseContext, "tag for debugging").apply {
setFlags(
MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS or
MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS )
mStateBuilder = PlaybackStateCompat.Builder()
.setActions(PlaybackStateCompat.ACTION_PLAY or PlaybackStateCompat.ACTION_PLAY_PAUSE)
setPlaybackState(mStateBuilder.build())
setCallback(mMediaSessionCallback)
setSessionToken(sessionToken)
isActive = true
}
}
private var mAttrs: AudioAttributes? = null
private fun play(mediaSource: MediaSource) {
if (mExoPlayer == null) initializePlayer()
mExoPlayer?.apply {
mAttrs?.let { initializeAttributes() }
mAttrs?.let { setAudioAttributes(it, true) }
prepare(mediaSource)
seekTo(currentWindow, playbackPosition)
playWhenReady = true
}
}
private fun play() {
mExoPlayer?.apply {
mExoPlayer?.playWhenReady = true
updatePlaybackState(PlaybackStateCompat.STATE_PLAYING)
mMediaSession?.isActive = true
}
}
private fun initializePlayer() {
mExoPlayer = ExoPlayerFactory.newSimpleInstance(
this, DefaultRenderersFactory(baseContext)
, DefaultTrackSelector(),
DefaultLoadControl()
)
}
private fun pause() {
mExoPlayer?.apply {
playWhenReady = false
if (playbackState == PlaybackStateCompat.STATE_PLAYING) {
updatePlaybackState(PlaybackStateCompat.STATE_PAUSED)
}
}
}
private fun stop() {
mExoPlayer?.playWhenReady = false
mExoPlayer?.release()
mExoPlayer = null
updatePlaybackState(PlaybackStateCompat.STATE_NONE)
mMediaSession?.isActive = false
mMediaSession?.release()
}
override fun onTaskRemoved(rootIntent: Intent?) {
super.onTaskRemoved(rootIntent)
stopSelf()
}
override fun onDestroy() {
super.onDestroy()
stop()
}
private fun updatePlaybackState(state: Int) {
mMediaSession?.setPlaybackState(
PlaybackStateCompat.Builder().setState(
state
, 0L
, 1.0f // Speed playing
).build()
)
}
private fun initializeAttributes() {
mAttrs = AudioAttributes.Builder().setUsage(C.USAGE_MEDIA)
.setContentType(C.CONTENT_TYPE_MUSIC)
.build()
}
private lateinit var mExtractorFactory: ExtractorMediaSource.Factory
private fun initializeExtractor() {
val userAgent = Util.getUserAgent(baseContext, "Application Name")
mExtractorFactory = ExtractorMediaSource.Factory(DefaultDataSourceFactory(this, userAgent))
.setExtractorsFactory(DefaultExtractorsFactory())
}
private fun extractMediaSourceFromUri(uri: Uri): MediaSource {
return mExtractorFactory.createMediaSource(uri)
}
override fun onLoadChildren(parentId: String, result: Result<MutableList<MediaBrowserCompat.MediaItem>>) {
}
override fun onGetRoot(clientPackageName: String, clientUid: Int, rootHints: Bundle?): BrowserRoot? {
return BrowserRoot("", null)
}
playerAct.kt
var audioUrlPass = ""
class playerAct: AppCompatActivity() { private val songUrl: String = audioUrlPass
private lateinit var mMediaBrowserCompat: MediaBrowserCompat
private val connectionCallback: MediaBrowserCompat.ConnectionCallback = object : MediaBrowserCompat.ConnectionCallback() {
override fun onConnected() {
super.onConnected()
mMediaBrowserCompat.sessionToken.also { token ->
val mediaController = MediaControllerCompat(this#playerAct, token)
MediaControllerCompat.setMediaController(this#playerAct, mediaController)
}
playPauseBuild()
}
override fun onConnectionFailed() {
super.onConnectionFailed()
}
}
private val mControllerCallback = object : MediaControllerCompat.Callback() {
}
fun playPauseBuild() {
val mediaController = MediaControllerCompat.getMediaController(this#playerAct)
main_pcv.showTimeoutMs = 0
exo_play.setOnClickListener {
val state = mediaController.playbackState.state
if (state == PlaybackStateCompat.STATE_PAUSED ||
state == PlaybackStateCompat.STATE_STOPPED ||
state == PlaybackStateCompat.STATE_NONE
) {
mediaController.transportControls.playFromUri(Uri.parse(songUrl), null)
}
else if (state == PlaybackStateCompat.STATE_PLAYING ||
state == PlaybackStateCompat.STATE_BUFFERING ||
state == PlaybackStateCompat.STATE_CONNECTING
) {
mediaController.transportControls.pause()
}
}
mediaController.registerCallback(mControllerCallback)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.player_layout)
val componentName = ComponentName(this, MusicService::class.java)
mMediaBrowserCompat = MediaBrowserCompat(
this, componentName, //Identifier for the service
connectionCallback,
null
)
menuButton.setOnClickListener {
super.onBackPressed()
}
btnTime1.setOnClickListener {
val intent = Intent(this, TimerActivity::class.java)
startActivity(intent)
}
playerSeekBar.setOnSeekBarChangeListener(
object : SeekBar.OnSeekBarChangeListener{
override fun onProgressChanged(seekbar: SeekBar?, progress: Int, fromUser: Boolean) {
if (fromUser){
val volumeNum = progress / 100.0f
mExoPlayer!!.setVolume(volumeNum)
}
}
override fun onStartTrackingTouch(seekbar: SeekBar?) { }
override fun onStopTrackingTouch(seekbar: SeekBar?) { }
})
}
override fun onStart() {
super.onStart()controller
Intent(this, MusicService::class.java).also {
mMediaBrowserCompat.connect()
}
}
override fun onStop() {
super.onStop()
val controllerCompat = MediaControllerCompat.getMediaController(this)
controllerCompat?.unregisterCallback(mControllerCallback)
mMediaBrowserCompat.disconnect()
}
}
In order to start the foreground service, you will need a notification shown within 5 seconds of starting it. Check the following guide in the android documentation: https://developer.android.com/guide/topics/media-apps/audio-app/building-a-mediabrowserservice#mediastyle-notifications
Following is my service class
class LocalAudioService : Service() {
var player: SimpleExoPlayer? = null
private var playerNotificationManager: PlayerNotificationManager? = null
private var mediaSession: MediaSessionCompat? = null
private var mediaSessionConnector: MediaSessionConnector? = null
private var allInOneApplication: AllInOneApplication? = null
private val binder = LocalBinder()
override fun onDestroy() {
mediaSession?.release()
mediaSessionConnector?.setPlayer(null, null)
playerNotificationManager?.setPlayer(null)
player?.release()
player = null
super.onDestroy()
}
override fun onBind(p0: Intent?): IBinder? {
return binder
}
fun getPlayerInstance(): SimpleExoPlayer? {
if (player == null) {
startPlayer()
}
return player
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if(player == null){
startPlayer()
}
return START_STICKY
}
private fun startPlayer(){
val videoTrackSelectionFactory = AdaptiveTrackSelection.Factory()
val trackSelector = DefaultTrackSelector(this, videoTrackSelectionFactory)
allInOneApplication = AllInOneApplication.getInstance()
val renderersFactory = (application as AllInOneApplication).buildRenderersFactory(false)
player =
SimpleExoPlayer.Builder(this, renderersFactory).setTrackSelector(trackSelector).build()
val dataSourceFactory = DefaultDataSourceFactory(
this,
Util.getUserAgent(this, getString(R.string.app_name))
)
// val cacheDataSourceFactory = CacheDataSourceFactory(
// DownloadUtil.getCache(this),
// dataSourceFactory,
// CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR
// )
val concatenatingMediaSource = ConcatenatingMediaSource()
allInOneApplication?.localAudios?.map {
val mediaSource = ProgressiveMediaSource.Factory(dataSourceFactory)
.createMediaSource(it?.audioUri)
concatenatingMediaSource.addMediaSource(mediaSource)
}
player?.prepare(concatenatingMediaSource)
player?.playWhenReady = true
playerNotificationManager = PlayerNotificationManager.createWithNotificationChannel(
this,
AUDIO_CHANNEL_ID,
R.string.audio_channel_name,
R.string.audio_channel_name,
NOTIFICATION_ID,
object : MediaDescriptionAdapter {
override fun createCurrentContentIntent(player: Player): PendingIntent? {
val intent = Intent(this#LocalAudioService, LocalAudioPlayer::class.java)
return PendingIntent.getActivity(
this#LocalAudioService,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT
)
}
override fun getCurrentContentText(player: Player): CharSequence? {
return allInOneApplication?.localAudios?.get(player.currentWindowIndex)?.title
}
override fun getCurrentContentTitle(player: Player): CharSequence {
return allInOneApplication?.localAudios?.get(player.currentWindowIndex)?.title.toString()
}
override fun getCurrentLargeIcon(
player: Player,
callback: PlayerNotificationManager.BitmapCallback
): Bitmap? {
return BitmapFactory.decodeResource(resources, R.drawable.audio)
}
}, object : PlayerNotificationManager.NotificationListener {
override fun onNotificationPosted(
notificationId: Int,
notification: Notification,
ongoing: Boolean
) {
startForeground(notificationId, notification)
}
override fun onNotificationCancelled(
notificationId: Int,
dismissedByUser: Boolean
) {
stopSelf()
}
}
)
playerNotificationManager?.setPlayer(player)
mediaSession = MediaSessionCompat(this, MEDIA_SESSION_TAG)
mediaSession?.isActive = true
mediaSession?.sessionToken?.let { playerNotificationManager?.setMediaSessionToken(it) }
mediaSessionConnector = MediaSessionConnector(mediaSession)
mediaSessionConnector?.setQueueNavigator(object : TimelineQueueNavigator(mediaSession) {
override fun getMediaDescription(
player: Player?,
windowIndex: Int
): MediaDescriptionCompat? {
return allInOneApplication?.getMediaDescription(
this#LocalAudioService,
allInOneApplication?.localAudios?.get(windowIndex)
)
}
})
mediaSessionConnector?.setPlayer(player, null)
}
inner class LocalBinder : Binder() {
val service: LocalAudioService
get() = this#LocalAudioService
}
}
Following is my Activity class
class LocalAudioPlayer : AppCompatActivity() {
private var localAudioService: LocalAudioService? = null
private var mBound = false
private val mConnection: ServiceConnection = object : ServiceConnection {
override fun onServiceConnected(componentName: ComponentName, iBinder: IBinder) {
val binder: LocalAudioService.LocalBinder = iBinder as LocalAudioService.LocalBinder
localAudioService = binder.service
mBound = true
initializePlayer()
}
override fun onServiceDisconnected(componentName: ComponentName) {
mBound = false
}
}
private fun initializePlayer() {
if (mBound) {
val player: SimpleExoPlayer? = localAudioService?.getPlayerInstance()
exoplayer_local_audio_player.player = player
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_local_audio_player)
Intent(this,LocalAudioService::class.java).also {
Util.startForegroundService(this,it)
exoplayer_local_audio_player.useController = true
exoplayer_local_audio_player.showController()
exoplayer_local_audio_player.controllerAutoShow = true
exoplayer_local_audio_player.controllerHideOnTouch = false
}
}
override fun onStart() {
super.onStart()
bindService(intent,mConnection, Context.BIND_AUTO_CREATE)
initializePlayer()
//TODO do any UI setup
}
override fun onStop() {
unbindService(mConnection)
mBound = false
super.onStop()
}
}
I tried following this question Binding PlayerView with SimpleExoPlayer from a service but the sole does not works for me
Try this:
override fun onStart() {
super.onStart()
Intent(this, LocalAudioService::class.java).also { intent ->
bindService(intent, mConnection, Context.BIND_AUTO_CREATE)
}
}
initializePlayer() should not be called here. At this moment the Service is not bound yet. When the service is bound it will called in the onServiceConnected callback.
bindService(intent,mConnection, Context.BIND_AUTO_CREATE)
intent is null here . Do Asure you are getting correct and non null intent.It should be global declared as in reference example
intent = new Intent(this, AudioPlayerService.class);
here intent is globally declared.
I am trying to play audio using exoplayer.
I have multiple files in a local directory and I want to play them sequentially. I am trying to add multiple to URIs to MediaSource, but I couldn't find the solution.
Here, the first file is playing correctly but none of the rest. I am using the ExoPlayer version 2.9.2
Note: In my case the files in the "Articles" folder will be updated dynamically while player is running.
Please suggest a solution. My code:
class AudioPlayerService : Service() {
private var player: SimpleExoPlayer? = null
private var playerNotificationManager: PlayerNotificationManager? = null
private var mediaSession: MediaSessionCompat? = null
private var mediaSessionConnector: MediaSessionConnector? = null
private var dataSourceFactory: DataSource.Factory? = null
private var extractorsFactory: ExtractorsFactory? = null
private var dynamicConcatenatingMediaSource: ConcatenatingMediaSource? = null
override fun onCreate() {
super.onCreate()
val context: Context = this
player = ExoPlayerFactory.newSimpleInstance(this)
dataSourceFactory = DefaultDataSourceFactory(context, BuildConfig.APPLICATION_ID)
extractorsFactory = DefaultExtractorsFactory()
var file: File = File(Environment.getExternalStorageDirectory().absolutePath + "/Articles")
/*for (i in file.listFiles()){
Log.e("","" +file.listFiles())
}*/
var uri =
Uri.parse(Environment.getExternalStorageDirectory().absolutePath + "/Articles" + "/article_tts" + 0 + ".wav")
//if (dynamicConcatenatingMediaSource == null)
dynamicConcatenatingMediaSource = ConcatenatingMediaSource()
val mediaSource: MediaSource =
ExtractorMediaSource.Factory(dataSourceFactory).createMediaSource(uri)
dynamicConcatenatingMediaSource?.addMediaSource(mediaSource)
player?.prepare(dynamicConcatenatingMediaSource)
player?.setPlayWhenReady(true)
player?.addListener(object : Player.EventListener {
override fun onTracksChanged(
trackGroups: TrackGroupArray?,
trackSelections: TrackSelectionArray?
) {
}
override fun onPlayerError(error: ExoPlaybackException?) {
stopSelf()
}
override fun onLoadingChanged(isLoading: Boolean) {
}
override fun onPositionDiscontinuity(reason: Int) {
}
override fun onRepeatModeChanged(repeatMode: Int) {
}
override fun onShuffleModeEnabledChanged(shuffleModeEnabled: Boolean) {
}
override fun onTimelineChanged(timeline: Timeline?, manifest: Any?, reason: Int) {
}
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
if (playbackState == Player.STATE_ENDED) {
player?.stop()
stopSelf()
}
}
override fun onSeekProcessed() {
}
override fun onPlaybackParametersChanged(playbackParameters: PlaybackParameters?) {
}
})
playerNotificationManager = PlayerNotificationManager.createWithNotificationChannel(
context,
"playback_channel",
R.string.playback_channel_name,
7001,
object : MediaDescriptionAdapter {
override fun getCurrentContentTitle(player: Player): String {
return "Playlist"
}
override fun createCurrentContentIntent(player: Player): PendingIntent? {
return null
}
override fun getCurrentContentText(player: Player): String? {
return "Playlist Demo"
}
override fun getCurrentLargeIcon(
player: Player,
callback: BitmapCallback
): Bitmap? {
return getBitmap(context, R.drawable.ic_vikatan_logo_new)
}
}
)
playerNotificationManager?.setNotificationListener(object :
PlayerNotificationManager.NotificationListener {
override fun onNotificationStarted(
notificationId: Int,
notification: Notification
) {
startForeground(notificationId, notification)
}
override fun onNotificationCancelled(notificationId: Int) {
stopSelf()
}
})
playerNotificationManager?.setPriority(NotificationCompat.PRIORITY_HIGH);
playerNotificationManager?.setUseNavigationActions(false)
playerNotificationManager?.setFastForwardIncrementMs(0)
playerNotificationManager?.setRewindIncrementMs(0)
playerNotificationManager?.setUsePlayPauseActions(true);
playerNotificationManager?.setPlayer(player)
mediaSession = MediaSessionCompat(context, "audio")
mediaSession?.setActive(true)
playerNotificationManager?.setMediaSessionToken(mediaSession?.getSessionToken())
mediaSessionConnector = MediaSessionConnector(mediaSession)
mediaSessionConnector?.setQueueNavigator(object : TimelineQueueNavigator(mediaSession) {
override fun getMediaDescription(
player: Player,
windowIndex: Int
): MediaDescriptionCompat {
return getMediaDescription(context)
}
})
mediaSessionConnector?.setPlayer(player, null)
}
override fun onDestroy() {
mediaSession!!.release()
mediaSessionConnector!!.setPlayer(null, null)
playerNotificationManager!!.setPlayer(null)
player!!.release()
player = null
super.onDestroy()
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return START_STICKY
}
fun getBitmap(context: Context, #DrawableRes bitmapResource: Int): Bitmap {
return (context.resources.getDrawable(bitmapResource) as BitmapDrawable).bitmap
}
fun getMediaDescription(context: Context?): MediaDescriptionCompat {
val extras = Bundle()
val bitmap: Bitmap = getBitmap(context!!, R.drawable.ic_vikatan_logo_new)
extras.putParcelable(
MediaMetadataCompat.METADATA_KEY_ALBUM_ART,
bitmap
)
extras.putParcelable(
MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON,
bitmap
)
return MediaDescriptionCompat.Builder()
.setMediaId("audio_id")
.setIconBitmap(bitmap)
.setTitle("Playlist")
.setDescription("Playlist Demo")
.setExtras(extras)
.build()
}
}
Use the concatenating media source.
private val concatenatingMediaSource = ConcatenatingMediaSource()
Then create separate mediasource for each audio file and add to concatenatingMediaSource by using
concatenatingMediaSource.addMediaSource(your_media_source_object)
How can I play a music file in the background through all activities by using Kotlin? I have looked everywhere but I only found solutions for Java not for Kotlin.
I tried using this function but I don't know how to use it:
fun playSound() {
try {
if (m.isPlaying()) {
m.stop()
m.release()
//m = MediaPlayer()
}
val descriptor = assets.openFd("backgroundsound1.mp3")
m.setDataSource(descriptor.fileDescriptor, descriptor.startOffset, descriptor.length)
descriptor.close()
m.prepare()
m.setVolume(1f, 1f)
m.setLooping(true)
m.start()
} catch (e: Exception) {
e.printStackTrace()
}
}
Here' code in kotlin code Play background music in all activities
class BackgroundSoundService : Service() {
internal lateinit var player: MediaPlayer
override fun onBind(arg0: Intent): IBinder? {
return null
}
override fun onCreate() {
super.onCreate()
val afd = applicationContext.assets.openFd("backgroundsound1.wav") as AssetFileDescriptor
val player = MediaPlayer()
player.setDataSource(afd.fileDescriptor)
player.isLooping = true // Set looping
player.setVolume(100f, 100f)
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
player.start()
return 1
}
override fun onStart(intent: Intent, startId: Int) {
// TO DO
}
fun onUnBind(arg0: Intent): IBinder? {
// TO DO Auto-generated method
return null
}
fun onStop() {
}
fun onPause() {
}
override fun onDestroy() {
player.stop()
player.release()
}
override fun onLowMemory() {
}
companion object {
private val TAG: String? = null
}
}
I am trying to set the notification icon in my player which is using exoplayer. I have a playlist and am using concatenatingMediaSource. I have the url of the album art for every song but I dont know how I can set it as the notification icon. I read some answers which suggested using a AsyncTask and creating the notification onPostExecute() but I don't see how I can do in exoplayer playerNotificationManager.
Here is my Audio Service class:-
class AudioPlayerService: Service() {
private var player: SimpleExoPlayer? = null
private var playerNotificationManager: PlayerNotificationManager? = null
private var mediaSession: MediaSessionCompat? = null
private var mediaSessionConnector: MediaSessionConnector? = null
private var songList: ArrayList<MetaData>? = null
private var context: Context? = null
override fun onCreate() {
super.onCreate()
context = this
val descriptionAdapter = object : PlayerNotificationManager.MediaDescriptionAdapter {
override fun getCurrentContentTitle(player: Player?): String {
return songList!![player!!.currentWindowIndex].name
}
override fun getCurrentContentText(player: Player?): String? {
return songList!![player!!.currentWindowIndex].artist
}
override fun getCurrentLargeIcon(player: Player?, callback: PlayerNotificationManager.BitmapCallback?): Bitmap? {
return null
}
override fun createCurrentContentIntent(player: Player?): PendingIntent? {
val intent = Intent(context, MainActivity::class.java)
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
}
playerNotificationManager = PlayerNotificationManager.createWithNotificationChannel(
this, "1", R.string.notification_name, 1, descriptionAdapter
)
val notificationListener = object : PlayerNotificationManager.NotificationListener {
override fun onNotificationStarted(notificationId: Int, notification: Notification?) {
startForeground(notificationId, notification)
}
override fun onNotificationCancelled(notificationId: Int) {
stopSelf()
}
}
playerNotificationManager!!.setNotificationListener(
notificationListener
)
mediaSession = MediaSessionCompat(context, "Test")
mediaSession!!.isActive = true
playerNotificationManager!!.setMediaSessionToken(mediaSession!!.sessionToken)
mediaSessionConnector = MediaSessionConnector(mediaSession)
val timelineQueueNavigator = object: TimelineQueueNavigator(mediaSession) {
override fun getMediaDescription(player: Player?, windowIndex: Int): MediaDescriptionCompat {
return getMediaDescription(songList!![windowIndex])
}
}
mediaSessionConnector!!.setQueueNavigator(timelineQueueNavigator)
}
override fun onDestroy() {
super.onDestroy()
mediaSession!!.release()
mediaSessionConnector!!.setPlayer(null, null)
playerNotificationManager!!.setPlayer(null)
player!!.release()
player = null
}
override fun onBind(p0: Intent?): IBinder? {
return null
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
songList = intent!!.getParcelableArrayListExtra<MetaData>("list")
context = this
player = ExoPlayerFactory.newSimpleInstance(this, DefaultTrackSelector())
val dataSource = DefaultDataSourceFactory(
this, Util.getUserAgent(this, getString(R.string.app_name)))
val concatenatingMediaSource = ConcatenatingMediaSource()
for(item in songList!!){
val mediaSource = ExtractorMediaSource.Factory(dataSource)
.createMediaSource(Uri.parse(item.url))
concatenatingMediaSource.addMediaSource(mediaSource)
}
player!!.prepare(concatenatingMediaSource)
player!!.playWhenReady = true
playerNotificationManager!!.setPlayer(player)
mediaSessionConnector!!.setPlayer(player, null)
return START_STICKY
}
private fun getMediaDescription(item: MetaData): MediaDescriptionCompat {
return MediaDescriptionCompat.Builder()
.setMediaId(item.id.toString())
.setTitle(item.name)
.setDescription(item.artist)
.setMediaUri(Uri.parse(item.url))
.build()
}
}
Thanks in advance.
You can use Glide for it in overrided function getCurrentLargeIcon
override fun getCurrentLargeIcon(
player: Player?,
callback: PlayerNotificationManager.BitmapCallback?
): Bitmap? {
loadBitmap(currentStation?.cover, callback)
return null //or stub image
}
private fun loadBitmap(url: String, callback: PlayerNotificationManager.BitmapCallback?) {
Glide.with(this)
.asBitmap()
.load(url)
.into(object : CustomTarget<Bitmap>() {
override fun onResourceReady(
resource: Bitmap,
transition: Transition<in Bitmap>?
) {
callback?.onBitmap(resource)
}
})
}
You need to override it like this
#Nullable
#Override
public Bitmap getCurrentLargeIcon(Player player, PlayerNotificationManager.BitmapCallback callback) {
Glide.with(this)
.asBitmap()
.load(uri)
.into(new CustomTarget<Bitmap>() {
#Override
public void onResourceReady(#NonNull Bitmap resource, #Nullable Transition<? super Bitmap> transition) {
callback.onBitmap(resource);
}
#Override
public void onLoadCleared(#Nullable Drawable placeholder) {
}
});
return null;
}