React-native-track-player: [iOS] Track Player stay in "loading" state when loading long audio.

Created on 4 May 2019  路  4Comments  路  Source: react-native-kit/react-native-track-player

Configuration

Run react-native info in your project and share the content.

React Native Environment Info:
    System:
      OS: macOS 10.14.4
      CPU: (8) x64 Intel(R) Core(TM) i5-8259U CPU @ 2.30GHz
      Memory: 50.72 MB / 8.00 GB
      Shell: 3.2.57 - /bin/bash
    Binaries:
      Node: 11.13.0 - /usr/local/bin/node
      Yarn: 1.15.2 - /usr/local/bin/yarn
      npm: 6.7.0 - /usr/local/bin/npm
      Watchman: 4.9.0 - /usr/local/bin/watchman
    SDKs:
      iOS SDK:
        Platforms: iOS 12.2, macOS 10.14, tvOS 12.2, watchOS 5.2
      Android SDK:
        API Levels: 27, 28
        Build Tools: 27.0.3, 28.0.3
        System Images: android-27 | Intel x86 Atom_64, android-28 | Google APIs Intel x86 Atom
    IDEs:
      Android Studio: 3.3 AI-182.5107.16.33.5199772
      Xcode: 10.2.1/10E1001 - /usr/bin/xcodebuild
    npmPackages:
      react: 16.8.3 => 16.8.3 
      react-native: 0.59.3 => 0.59.3 
    npmGlobalPackages:
      react-native-cli: 2.0.1

What react-native-track-player version are you using?
^1.1.3

Issue

Hi everyone. So I am making a react-native project streaming music. My application works fine with short track, but when it comes to longer ( from 20 minutes to hours ), the problem arises:

  1. State of TrackPlayer stuck at 'Loading' even when track have successfully added to the queue. (I found out that it is not the case. Because any tracks that have required fields can be added to the queue)
  2. TrackPlayer.getDuration() return 0. I initialized track with duration property so it is not the problem when Track Player try to calculate the length of track.
  3. If I try to force it to play by using TrackPlayer.play(); method, state of TrackPlayer changes but the music doesn't come out. In some scenario, it comes back to 'loading' state.
  4. Everything back to normal when I change to another track and comeback to this track.

I'm sure it is the problem with the Track Player because I let the player wait for minutes but it is still loading, but when i change the track, the problem immediately solves.

Code

import React, { Component } from 'react';
import TrackPlayer from 'react-native-track-player';
import { Header, AlbumArt, TrackDetails, SeekBar, PlaybackControl, Spinner } from './common'
import { TextInput, Button, SafeAreaView, Text, View } from 'react-native';
import axios from 'axios';
import memoize from "memoize-one";
import moment from 'moment';

export default class PlayScreen extends Component {
  constructor(props) {
    super(props);
    this.state = {
      track: null,
      paused: true,
      isLoading: false,
      shuffleOn: false,
      repeatOn: true
    };
  }
  onPressPause() {
    this.setState({ paused: true });
    TrackPlayer.pause();
  }
  onPressPlay() {
    this.setState({ paused: false })
    TrackPlayer.play();
  }
  onPressRepeat() {
    this.setState((state) => {
      return {repeatOn: !this.state.repeatOn}
    })
  }
  async onPressBack() {
    await TrackPlayer.skipToPrevious();
  }
  async onPressForward() {
    await TrackPlayer.skipToNext();
  }
  initializeTrack(videoId) {
    // initialize track ( loading track from url )
      return track;
  }
  async addAndPlay(track) {
    TrackPlayer.add(track).then(async (result) => {
      /**
       * PURPOSE: wait until track player have finished loading. Currently not work as expected 
       */
      console.log('add track result: ' + result);
      TrackPlayer.getState().then((playerState) => {
        console.log('track state ' + playerState)
        this.setState({ isLoading: false })
      })  

    });
    await TrackPlayer.skip(track.id)
    this.onPressPlay();
  }
  memoizedLoad = memoize(async (videoId) => {
    if(!videoId)
      return;
    TrackPlayer.pause();
    this.setState({ isLoading: true })
    let track = await this.initializeTrack(videoId)
    this.addAndPlay(track)
  })

  async getTheTrackQueue() {
    let tracks = await TrackPlayer.getQueue();
    console.log(tracks)
    TrackPlayer.getState().then((result) => console.log(result))
  }
  async componentDidUpdate() {
    this.memoizedLoad(this.props.navigation.getParam('videoId'));
  }
  componentWillUnmount() {
    // Removes the event handler
}
  async componentDidMount() {
    this.onTrackChange = TrackPlayer.addEventListener('playback-track-changed', async (data) => {
      let track = await TrackPlayer.getTrack(data.nextTrack);
      this.setState({track});
      this.setState({ paused: false });
  });
    this.memoizedLoad(this.props.navigation.getParam('videoId'));
  }

  render() {
    return (
      <SafeAreaView style={{ flex: 1, backgroundColor: 'gray' }}>
        <Header
          message="playing from fly"
          onQueuePress={this.getTheTrackQueue.bind(this)}
        />
        <AlbumArt url={!this.state.track ? "" : this.state.track.thumbnail.url} />
        <TrackDetails
          title={!this.state.track ? "" : this.state.track.title.slice(0, 30)}
        />
        <SeekBar
          trackLength={!this.state.track ? 0 :this.state.track.duration}
        />
        <PlaybackControl
          paused={this.state.paused}
          shuffleOn={this.state.shuffleOn}
          repeatOn={this.state.repeatOn}
          onPressPause={this.onPressPause.bind(this)}
          onPressPlay={this.onPressPlay.bind(this)}
          onPressRepeat={this.onPressRepeat.bind(this)}
          forwardDisabled={false}
          backwardDisabled={false}
          shuffleDisabled={true}
          onForward={this.onPressForward.bind(this)}
          onBack={this.onPressBack.bind(this)}
        />
        {this.state.isLoading ?
          <Spinner /> : <View />
        }
        <Button title='get duration' onPress={async() => {
          console.log(await TrackPlayer.getDuration())
        }}/>
        <Button title='force play' onPress={async() => {
          await TrackPlayer.remove(this.state.track.id)
          TrackPlayer.skip(this.state.track.id)
        }}/>
        <Button title='remove current' onPress={async() => {
          await TrackPlayer.remove(this.state.track.id)

        }}/>

      </SafeAreaView>
    );
  }
}
iOS

Most helpful comment

(if you are using the version 1.1.4) Maybe you should try to add

waitForBuffer: true

to PlayerOptions.

from some reason it is not documented, but it is part of the api

All 4 comments

Same problem here, In my case it is even worse because I am playing streams and RNTrackPlayer can never guess the duration.
I must also mention this problem is only present in iOS and my Android app is working properly.

(if you are using the version 1.1.4) Maybe you should try to add

waitForBuffer: true

to PlayerOptions.

from some reason it is not documented, but it is part of the api

Any update on this?

I was able to solve my problem with something like this https://github.com/react-native-kit/react-native-track-player/issues/533#issuecomment-492206711

Was this page helpful?
0 / 5 - 0 ratings

Related issues

KalebPortillo picture KalebPortillo  路  4Comments

amed picture amed  路  4Comments

moduval picture moduval  路  4Comments

elioscordo picture elioscordo  路  3Comments

ManrickCapotolan picture ManrickCapotolan  路  4Comments