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.27k stars 1.01k forks source link

[Feature Request] The example code for setting up the player is complicated and docs are insufficient - can you take the example setup code and productize it? #2344

Open eedeebee opened 3 months ago

eedeebee commented 3 months ago

Context These thoughts were triggered by my receiving an error in the field that is On Android the app must be in the foreground when setting up the player. and my realizing the code I have in index.js isn't sufficient (or perhaps incorrect) for robust rntp initialization.

I offer it below as an example with my app's other index.js goo left in (sorry).

What is the need and use case of this feature? The code in the example app here for setting up the player is complicated and the requirements are not really explained in the documentation (e.g., handling of initialization failures and retries). The published docs on how to set things up should be sufficient to cover what to do for your app to be robust in production, but they aren't.

Describe the ideal solution I would suggest re-working the initialization APIs and/or creating a higher level, simple API call or perhaps two. (This is par for the course for almost every other library.) One could define an object that takes in the information you need for initialization and then abstract away the complexity in the example as much as possible.

The code here is what I'm talking about. At one end of the spectrum, you could just move the example code into the library itself or some version of it that is slightly more general purpose.

Relatedly, with today's APIs, it's not clear the requirements are for ordering and timing of registering the playback service and setupPlayer. Which one needs to happen when? Updating the docs for that would be a helpful step.

Sample insufficient initialization code of mine

/**
 * @format
 */

import {AppRegistry} from 'react-native';
import {NavigationContainer} from '@react-navigation/native';
import App from './src/App';
import {name as appName} from './app.json';
import TrackPlayer, { IOSCategoryOptions, AppKilledPlaybackBehavior } from 'react-native-track-player';

import { QueryClient } from '@tanstack/react-query';
import AsyncStorage from '@react-native-async-storage/async-storage'
import { PersistQueryClientProvider } from '@tanstack/react-query-persist-client'
import { createAsyncStoragePersister } from '@tanstack/query-async-storage-persister'
import 'react-native-url-polyfill/auto';
import 'react-native-get-random-values';

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      gcTime: Infinity, // Let's hold things forever
    },
  },
});
const asyncStoragePersister = createAsyncStoragePersister({
  storage: AsyncStorage,
  key: "tanstack"
});

const NotewizeApp = () => (
    <NavigationContainer>
      <PersistQueryClientProvider client={queryClient} persistOptions={{ persister: asyncStoragePersister }}>
        <App/>
      </PersistQueryClientProvider>
    </NavigationContainer>
  );

AppRegistry.registerComponent(appName, () => NotewizeApp);

async function setupTrackPlayerAndLoadModel() {
  TrackPlayer.registerPlaybackService(() => require('./src/components/pages/Player/service.js'));
  await TrackPlayer.setupPlayer({
    iosCategoryOptions: [IOSCategoryOptions.AllowBluetoothA2DP]
  });
  await TrackPlayer.updateOptions({
    android: {
        appKilledPlaybackBehavior: AppKilledPlaybackBehavior.StopPlaybackAndRemoveNotification
    },
  });
  await TrackPlayer.setVolume(0.5);
  const chord = require("./android/app/src/main/res/raw/notewize_chord.mp3");
  await TrackPlayer.add({
    url: chord
  });
  TrackPlayer.play();

  await Audio.loadModel();
} 

setupTrackPlayerAndLoadModel();
github-actions[bot] commented 2 days ago

This issue is stale because it has been open 90 days with no activity. Remove stale label or comment or this will be closed in 7 days.

eedeebee commented 2 days ago

I believe this issue remains open. If someone could explain what is required here wrt properly initializating rntp, I'm more than happy to write some doc.

lovegaoshi commented 1 day ago

hard to say what happens with your setup code without some serious attention. but the general workflow (android) is:

  1. TP.setupPlayer from MusicModule (ie. the native module) starts MusicService, binds to it and set a connected flag on;
  2. most other TP methods require this connection, otherwise will reject with The player is not initialized. Call setupPlayer first

because of this it is advised to call TP.setupPlayer ASAP so any other TP calls can actually work.

I've never seen On Android the app must be in the foreground when setting up the player. typically people, including the example app, awaits TP.setupPlayer in whatever splash screen they set up. in the example app this is useSetupPlayer and nothing mounts until this hook returns ready.

these errors and retries are there because android is notorious for changing requirements over versions (in a way, becoming more secure as well). This lib dates from 2018. Although I can tell you the particular error you mention, On Android the app must be in the foreground when setting up the player. is largely irrelevant currently. It is correct that a background activity can no longer start a service, but MusicService, as a declared foreground service, should already be started by the system as app starts. This is somewhat illustrated in my recent discovery of the headless start capability.