New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Android runAsForeground issue #66
Comments
Which calls are you making while your app is in the background? |
Here are a few of the code that could be causing this issue: I run this code after an item in the playlist finishes (event 50 - playback completed) onPlaybackCompleted ({ episodeId } = {}) {
this.markEpisodeAsListened({ episodeId })
this.playlist = this.playlist.filter(ep => ep.id !== episodeId)
if (this.playlist.length > 0) {
this.playNextTrack()
this.play()
}
this.removeItem({ trackId: `${episodeId}` })
} Here I check if the playlist is actually done: /**
* 105: on event playlist completed
*/
case 105: {
console.log('on event playlist completed - msgType, value -> ', msgType, value);
const _hasPlayedAllEpisodes = this.hasPlayedAllEpisodes()
if (!_hasPlayedAllEpisodes) {
this.playNextTrack()
}
if (_hasPlayedAllEpisodes) {
this.onPlaylistCleared()
}
break;
} Do you think these could possibly be causing the issue? |
Guys, how did you manage to solve issue with build? I am still not able to successfully build android. Error I am getting is related to the plugin dependencies: FAILURE: Build completed with 8 failures. 1: Task failed with an exception.
|
Sorry for the late reply @podbasico. Did you figure this out? Is there a reason why you have to manually call play()? |
@Roshankd1 Do you have jcenter() as a repository under you project level build.gradle? I vaguely remember having this issue. As you can see the resource says it's located at jcenter() for version 4.3.0 of Exomedia https://mvnrepository.com/artifact/com.devbrackets.android/exomedia/4.3.0 |
@emilsaj You saved my day! Thank you so so much :) |
@emilsaj quick question! is there a way to delay 4 secs after playing every audio file? thanks a ton. |
@Roshankd1 Not sure that's gonna work on Android when playing in the background - I would not think so. Even iOS might not work if audio is suspended and then started without user interaction, but I am not sure. |
Yes I have been trying to listen to complete event - 50 and set timeout, so i can loop within the array of files and play once at a time by invoking playbyTrackId func but something is not working. I will let you know if I make any improvements on this end. |
Thanks for the reply. But I'm still getting lots of these errors, and not sure how to solve it (this is my first app). Here is my player implementation: export class PlayerService {
constructor (app) {
this.app = app
this.currentPosition = 0
this.platform = platform
this.player = new RmxAudioPlayer()
this.player.initialize()
this.hasFinishedPlayingBefore = false
this.shouldSetPlaybackRateFromLocalStorage = false
// counter is used to send request to update currentTime on server
this.counter = 0
this.player.on('status', (data = {}) => {
const { msgType, trackId, value } = data
if (msgType && trackId) {
try {
this.onStatusChanged({ msgType, trackId, value })
} catch (error) {
console.error('error', error)
throw error
}
}
});
}
play () {
try {
this.player.play();
} catch (error) {
throw error
}
}
pause () {
try {
this.player.pause();
} catch (error) {
throw error
}
}
async setPlaylist ({ tracks = [], episodeId, currentPosition = 0 } = {}) {
try {
const options = {
playFromPosition: currentPosition,
startPaused: false,
retainPosition: true,
playFromId: `${episodeId}`
};
this.player.setPlaylistItems(tracks, options)
this.currentPosition = currentPosition
return
} catch (error) {
console.error('error', error)
throw error
}
}
async playTrackById (id, position) {
this.currentPosition = position
return await this.player.playTrackById(`${id}`, position)
}
setPlaybackRate(playbackRate) {
if (typeof playbackRate !== 'number') return
return this.player.setPlaybackRate(playbackRate);
}
async setPlayerOptions () {
const options = {
verbose: process.env.PROD
}
if (platform === 'ios') {
options.options = { icon: 'icon_bw' }
}
if (platform === 'android') {
options.options = { icon: 'ic_stat_ic_notification' }
}
await this.player.setOptions(options);
}
seekTo({ position } = {}) {
const wasPlaying = this.isPlaying;
this.player.seekTo(position).then(() => {
this.currentPosition = position
// this is due to iOS not holding playbackRate
if (this.platform === 'ios') {
this.shouldSetPlaybackRateFromLocalStorage = false
}
if (wasPlaying) {
return this.player.play();
}
})
}
async addItem (trackItem) {
return await this.player.addItem(trackItem)
}
async removeItem (trackItem) {
return await this.player.removeItem(trackItem)
}
async selectTrackById (trackId, currentPosition) {
return await this.player.selectTrackById(trackId, currentPosition)
}
get getCurrentTrackId () {
return this.player.currentTrack && this.player.currentTrack.trackId
}
get currentItem () {
return this.player.currentTrack
}
get isPlaying () {
return this.player.currentState === 'playing';
}
get isPaused () {
return this.player.currentState === 'paused';
}
async onPositionChanged ({ trackId, value }) {
let { currentPosition } = value
// Math.trunc returns the integer part of a number by removing a ny fractional digits
currentPosition = Math.trunc(currentPosition)
if (currentPosition === 0) return
this.currentPosition = currentPosition
this.counter++
this.app.store.dispatch('episodes/setEpisodeCurrentPosition', { currentPosition, episodeId: Number(trackId) })
// every x seconds I save the user progress on server
if (this.counter >= APP_INTERVAL_SEND_UPDATE_POSITION_REQUEST_IN_SECONDS) {
this.counter = 0
try {
this.saveUserCurrentPosition({ episodeId: trackId, currentPosition })
} catch (error) {
console.error('error', error)
}
}
// this is to fix iOS not holding playback value
if (this.platform === 'ios' && this.shouldSetPlaybackRateFromLocalStorage === false && this.isPlaying) {
this.shouldSetPlaybackRateFromLocalStorage = true
this.setPlaybackRateFromLocalStorage()
}
}
async setPlaybackRateFromLocalStorage () {
try {
// const playbackRate = await this.getPlaybackRateFromLocalStorage()
const playbackRate = await get(idbKey) || 1
this.setPlaybackRate(playbackRate)
} catch (error) {
// console.log('error', error)
throw error
}
}
onStatusChanged ({ value, msgType, trackId } = {}) {
if (!msgType || !trackId) {
// alert('onStatusChanged error msgType, trackId -> ', msgType, trackId)
return
}
const trackIdNumber = Number(trackId)
switch (msgType) {
/**
* 30: event on playing
* ios: on
* web: on
* android: on
*/
case 30: {
// console.log('event on playing - msgType, value -> ', msgType, value);
if (trackId && trackIdNumber) {
this.app.store.dispatch('episodes/updateEpisodeToPlaying', { episodeId: trackIdNumber })
}
break;
}
/**
* 35: event on paused
*/
case 35: {
// console.log('event on paused - msgType, value -> ', msgType, value);
if (this.platform === 'ios') {
setTimeout(() => {
this.shouldSetPlaybackRateFromLocalStorage = false
}, 300)
}
if (this.platform === 'android' && trackId && trackIdNumber) {
this.app.store.dispatch('episodes/updateEpisodeToPause', { episodeId: trackIdNumber })
}
break;
}
/**
* 40: event on playback position changed
*/
case 40: {
// console.log('event on playback position changed - msgType, value -> ', msgType, value);
const positionChangeCallback = ({ value, trackId }) => {
this.onPositionChanged({ value, trackId })
}
if (!throttleFunc) {
throttleFunc = throttle(positionChangeCallback, 1000)
}
throttleFunc({ value, trackId })
break;
}
/**
* 50: event on playback completed
*/
case 50: {
// console.log('event on playback completed - msgType, value -> ', msgType, value);
this.app.store.dispatch('episodes/updateEpisodeToNotPlaying', { episodeId: trackIdNumber })
this.app.store.dispatch('episodes/markEpisodeAsListened', { episodeId: trackIdNumber })
this.app.store.dispatch('episodes/removeEpisodeFromPlaylist', { episodeId: trackIdNumber })
this.currentPosition = 0
const hasEpisodeInPlaylist = this.app.store.getters['episodes/hasEpisodeInPlaylist']
if (!hasEpisodeInPlaylist) {
const message = 'Lista de reprodução concluída!'
Notify.create({ message, type: 'positive' })
this.hasFinishedPlayingBefore = true
}
break;
}
/**
* 100: event track changed
* web: on
* ios: on
* android: on
*/
case 100: {
if (platform === 'android' || platform === 'ios') {
const playingEpisode = this.app.store.getters['episodes/getPlaying']
const episodeId = playingEpisode && playingEpisode.id
// first click to play an episode these values should be the same
if (episodeId === trackIdNumber) return
if (episodeId) {
this.app.store.dispatch('episodes/updateEpisodeToNotPlaying', { episodeId })
}
this.app.store.dispatch('episodes/updateEpisodeToPlaying', { episodeId: trackIdNumber })
}
break;
}
default: {
}
}
}
async saveUserCurrentPosition ({ currentPosition, episodeId } = {}) {
try {
saveUserPosition({ episodeId: `${episodeId}`, currentPosition })
this.counter = 0
} catch (error) {
console.error('error', error)
throw error
}
}
} |
@podbasico from your code snippet I would say it looks somewhat like my implementation. |
Nope I'm not, on a previous version of my APP I was doing that, but then realized it could be the reason for the issues. |
@emilsaj @podbasico Guys I am getting an issue with background play even after setting the permission in manifest as instructed in readme. |
Is anyone getting this error below? I have seen lots of it in my logs.
cc: @emilsaj
The text was updated successfully, but these errors were encountered: