doublesymmetry / react-native-track-player

A fully fledged audio module created for music apps. Provides audio playback, external media controls, background mode and more!
https://rntp.dev/
Apache License 2.0
3.2k stars 984 forks source link

NotificationCapabilities next and previous action button is not working in background mode. #592

Closed RohitNNaik closed 5 years ago

RohitNNaik commented 5 years ago

Configuration

Run react-native info in your project and share the content. What react-native-track-player version are you using?

Issue

Code

Show us the code you are using

RohitNNaik commented 5 years ago

react-native-track-player: 1.1.4, react-native: 0.59.8

brenwell commented 5 years ago

More info perhaps?

RohitNNaik commented 5 years ago

Player.js

import React from 'react' import {View, Text, TouchableOpacity, Image,ActivityIndicator} from 'react-native' import TrackPlayer, {ProgressComponent} from 'react-native-track-player'; import Tracker from '../Tracker';

export default class Player extends React.Component{

constructor()
{
    super()
    this.state = {
        AudioStatus: true,
        isLoadingPlay:false,
        isLoadingPrev:false,
        isLoadingNext:false,
    };
}

componentDidMount() {
    TrackPlayer.setupPlayer();
    TrackPlayer.updateOptions({
        stopWithApp: true,
        compactCapabilities: [
          TrackPlayer.CAPABILITY_PLAY,
          TrackPlayer.CAPABILITY_PAUSE,
          //TrackPlayer.CAPABILITY_STOP,
          TrackPlayer.CAPABILITY_SKIP_TO_NEXT,
          TrackPlayer.CAPABILITY_SKIP_TO_PREVIOUS
        ],
        capabilities: [
            TrackPlayer.CAPABILITY_PLAY,
            TrackPlayer.CAPABILITY_PAUSE,
            TrackPlayer.CAPABILITY_SKIP_TO_NEXT,
            TrackPlayer.CAPABILITY_SKIP_TO_PREVIOUS,
        ],
        notificationCapabilities:[
          TrackPlayer.CAPABILITY_PLAY,
          TrackPlayer.CAPABILITY_PAUSE,
          //TrackPlayer.CAPABILITY_STOP,
          TrackPlayer.CAPABILITY_SKIP_TO_NEXT,
          TrackPlayer.CAPABILITY_SKIP_TO_PREVIOUS
        ]

    });
}
togglePlayback = async () => {
    const currentTrack = await TrackPlayer.getCurrentTrack();

    if (currentTrack == null) {
      console.log("track is null")
      this.setState({
        AudioStatus: false,
        isLoadingPlay:true
    });
      TrackPlayer.reset();
      await TrackPlayer.add(data);
      TrackPlayer.play();
      this.setState({
        isLoadingPlay:false
      })
    }
    else {
        if(this.state.AudioStatus){
          console.log("play")
            this.setState({
                AudioStatus: false
            });
            TrackPlayer.play();
        }else{
          console.log('pause')
            this.setState({
                AudioStatus: true
            });
            TrackPlayer.pause();
        }
      console.log('else...', TrackPlayer.STATE_PLAYING);
    }
  }

  skipToNext = async () => {
    this.setState({
        AudioStatus: false,
        isLoadingPlay:true
    });
    try {
      await TrackPlayer.skipToNext()
    } catch (_) {
      TrackPlayer.reset();

    }
    this.setState({
      isLoadingPlay:false
    })
  }

  skipToPrevious = async () => {
    this.setState({
        AudioStatus: false,
        isLoadingPlay:true
    });
    try {
      await TrackPlayer.skipToPrevious()
    } catch (_) {}
    this.setState({
      isLoadingPlay:false
    })
  }
render(){

    return(
        <View style={{ justifyContent:'space-between', 
        backgroundColor: '#D8D8D8',
        //width:"90%",
        borderColor: 'black',
        borderWidth: 2,
        }}>
        <View style={{justifyContent:'center', alignItems:'center'}}>
        <Tracker/>
        <View style={{flexDirection: 'row', alignItems:'center'}}>
        <TouchableOpacity onPress={() => this.skipToPrevious()} style={{padding: 8}}>
             {this.state.LoadingPrev? <ActivityIndicator size='small' color='white' />:<Image source={{uri: 'http://icons.iconarchive.com/icons/iconsmind/outline/512/Back-Music-icon.png'}} style={{width: 40, height: 30}} resizeMode='contain'/>}
                    </TouchableOpacity>
                    <TouchableOpacity onPress={() => this.togglePlayback()} style={{padding: 8}}>
                    {this.state.isLoadingPlay? <ActivityIndicator size='small' color='white' />:<Image source={this.state.AudioStatus ? {uri: 'https://i0.wp.com/icons.iconarchive.com/icons/iconsmind/outline/512/Play-Music-icon.png'} 
                    : {uri: 'http://icons.iconarchive.com/icons/danieledesantis/audio-video-outline/512/pause-icon.png'}} style={{width: 40, height: 30}} resizeMode='contain'/>}
                    </TouchableOpacity>

                    <TouchableOpacity onPress={() => this.skipToNext()} style={{padding: 8}}>
                    {this.state.isLoadingNext? <ActivityIndicator size='small' color='white' />:<Image source={{uri: 'http://icons.iconarchive.com/icons/iconsmind/outline/512/Next-Music-icon.png'}} style={{width: 40, height: 30}} resizeMode='contain'/>}
                    </TouchableOpacity>
        </View>
        </View>
        </View>
    )
    }
    PlayAudio()
{
    if(this.state.AudioStatus){
        this.setState({
            AudioStatus: false
        });
        TrackPlayer.play();
    }else{
        this.setState({
            AudioStatus: true
        });
        TrackPlayer.pause();
    }
}

} TrackPlayer.registerEventHandler(require('../../player-handler.js')); const data = [ { "id": "1111", "url": 'http://www.usebuck.com/TestAudio/Whatsapp%20Status%20Video%20%20Heart%20Touching%20Songs%20%20Mohabbatein%20Love%20Songs%20%20Short%20Romantic%20Story.mp3', "title": "Longing", "artist": "David Chavez", "artwork": "https://picsum.photos/200" }, { "id": "2222", "url": "https://drive.google.com/uc?export=download&id=1VM9_umeyzJn0v1pRzR1BSm9y3IhZ3c0E", "title": "Soul Searching (Demo)", "artist": "David Chavez", "artwork": "https://picsum.photos/200" }, { "id": "3333", "url": "https://drive.google.com/uc?export=download&id=1bmvPOy2IVbkUROgm0dqiZry_miiL4OqI", "title": "Lullaby (Demo)", "artist": "David Chavez", "artwork": "https://picsum.photos/200" }, { "id": "4444", "url": "https://drive.google.com/uc?export=download&id=1V-c_WmanMA9i5BwfkmTs-605BQDsfyzC", "title": "Rhythm City (Demo)", "artist": "David Chavez", "artwork": "https://picsum.photos/200" } ]

Tracker.js

import React from 'react' import {View, Text, TouchableOpacity, Image} from 'react-native' import TrackPlayer, {ProgressComponent} from 'react-native-track-player'; import Slider from '@react-native-community/slider';

export default class TrackStatus extends TrackPlayer.ProgressComponent { state = { duration: 0, isSeeking: false, age:null } formatTime(seconds) {

   return seconds > 3600 
   ?
     [
       parseInt(seconds / 60 / 60),
       parseInt(seconds / 60 % 60),
       parseInt(seconds % 60)
     ].join(":").replace(/\b(\d)\b/g, "0$1")
   :
     [
       parseInt(seconds / 60 % 60),
       parseInt(seconds % 60)
     ].join(":").replace(/\b(\d)\b/g, "0$1")
 }
render () {
  TrackPlayer.getDuration().then(duration=>this.setState({duration}))
  return (
    <View>
      <View style={{flexDirection:'row', }}>
         <Text style={{color: 'black',backgroundColor:'transparent',textAlign:'center',width:40,fontSize:12,paddingTop:8}}>
          { this.state.isSeeking ? this.formatTime(this.seek) : this.formatTime(this.state.position) }
        </Text> 
        {console.log(this.state.duration)}
        <Slider 
          minimumValue          = {0}
          maximumValue          = {this.state.duration}
          //thumbTintColor        = "white"
          //minimumTrackTintColor = "#000"
          //maximumTrackTintColor = "rgba(255,255,255,.8)"
          step                  = {1}
          onValueChange ={ val=>{
            TrackPlayer.pause();
            this.seek = val;
            this.setState({isSeeking:true})
          }}
          onSlidingComplete={ val=>{
             this.setState({isSeeking: false },()=> {
              if(this.seek!= null){
              TrackPlayer.seekTo(this.seek);
              this.position = this.seek;
              TrackPlayer.play();
              //this.setState({isSeeking:false})
              }
            })
          }}
          value={this.state.isSeeking ? this.seek : this.state.position}
          style={{width: '75%',backgroundColor: '#FFFFFF'}}
        />
       <Text style={{padding:5,fontSize:12}}>{this.formatTime(this.state.duration)}</Text> 
      </View>
    </View>
  )
}

} TrackPlayer.registerEventHandler(require('../../player-handler.js'));

player-handler.js import TrackPlayer from "react-native-track-player";

module.exports = async (data) => { if(data.type === 'playback-state') { // Update the UI with the new state } else if(data.type === 'remote-play') { TrackPlayer.play(); } else if(data.type === 'remote-pause') { TrackPlayer.pause(); } else if(data.type === 'remote-stop') { TrackPlayer.stop(); } else if(data.type === 'remote-seek') { console.warn(data.position); TrackPlayer.seekTo(data.position); } };

brenwell commented 5 years ago

It would be cool if you would mention which platform it effects.

But my first guess is that you need to await

setupPlayer

RohitNNaik commented 5 years ago

platform ios as well as android

brenwell commented 5 years ago

What do you mean by "not working"? Buttons are greyed, events don't fire, something else.

Could you format the code with all the proper syntax markdown ```javascript please. hard to read on my phone

brenwell commented 5 years ago

Additionally you should read the docs here.

https://react-native-kit.github.io/react-native-track-player/documentation/#lifecycle-functions

registerEventHandler is deprecated

you should register events like this:

TrackPlayer.registerPlaybackService(() => require('./service'));

service.js

import TrackPlayer from 'react-native-track-player';

module.exports = async function() {

  TrackPlayer.addEventListener('remote-play', () => {
    TrackPlayer.play()
  })

  TrackPlayer.addEventListener('remote-pause', () => {
    TrackPlayer.pause()
  });

  TrackPlayer.addEventListener('remote-next', () => {
    TrackPlayer.skipToNext()
  });

  TrackPlayer.addEventListener('remote-previous', () => {
    TrackPlayer.skipToPrevious()
  });

  TrackPlayer.addEventListener('remote-stop', () => {
    TrackPlayer.destroy()
  });

};

https://github.com/react-native-kit/react-native-track-player/blob/dev/example/service.js

RohitNNaik commented 5 years ago

Ok thank you @brenwell

brenwell commented 5 years ago

If you workout what the issue was, please share it here with the community

brenwell commented 5 years ago

And??

RohitNNaik commented 5 years ago

This worked for me

import TrackPlayer from 'react-native-track-player';

module.exports = async function() {

TrackPlayer.addEventListener('remote-play', () => { TrackPlayer.play() })

TrackPlayer.addEventListener('remote-pause', () => { TrackPlayer.pause() });

TrackPlayer.addEventListener('remote-next', () => { TrackPlayer.skipToNext() });

TrackPlayer.addEventListener('remote-previous', () => { TrackPlayer.skipToPrevious() });

TrackPlayer.addEventListener('remote-stop', () => { TrackPlayer.destroy() });

};

OmkoBass commented 3 years ago

When you add a new capability, kill the react-native start process and the emulator, then start it again the capabilities will start working again.