1.1.0 • Published 10 months ago

audio-streaming v1.1.0

Weekly downloads
-
License
MIT
Repository
github
Last release
10 months ago

Installation

NPM

npm install audio-streaming

API

StreamingPlayer Methods

MethodDescription
initPlayer(options: StreamingOptions): Promise<any>Initializes the player with the provided audio URL and begins playback.
play(): voidStarts or resumes audio playback.
pause(): voidPauses the current audio playback.
release(): voidReleases resources associated with the audio player.
seekTo(time: number, callback?: () => void): voidJumps to a specified position in the audio track (in seconds), with an optional callback function.
setMediaSession(options: StreamingOptions, play: Function, pause: Function, nextEpisode: Function, previousEpisode: Function): Promise<void>Configures multimedia controls to allow actions like play, pause, next episode, and previous episode.
setNowPlayingInfo(options: StreamingOptions, currentTime: number): Promise<void>Updates metadata (like title, artist, duration, and artwork) for the current track to display on media control interfaces.
updatePlaybackState(isPlaying: boolean, currentTime: number): voidUpdates the playback state (playing or paused) and current playback time on the media interface.

StreamingPlayer Read-only Properties

Read-only propertiesDescription
currentTime: numberThe current playback time in seconds.
duration: numberThe total duration of the audio track in seconds.
isPlaying: booleanIndicates if the audio is currently playing.

StreamingOptions Properties

PropertiesDescription
audioUrl?: stringThe URL of the audio track to be streamed.
audioImageUrl?: stringThe URL of an image to represent the audio track, typically displayed in media controls and lock screens.
audioTitle?: stringThe title of the audio track, displayed in media control interfaces.
audioArtist?: stringThe artist or creator of the audio track, displayed alongside the title in media controls.

Usage

Nativescript-Vue 2, Vuex 3 and TypeScript 5 Example

// ./store/audio-streaming.ts
import { StreamingPlayer, StreamingOptions } from 'audio-streaming';
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

interface State {
    player: StreamingPlayer;
    options: StreamingOptions;
    timeUpdateInterval: any;
    currentTime: number;
    duration: number;
    isPlaying: boolean;
}

export default new Vuex.Store<State>({
    state: {
        player: new StreamingPlayer(),
        options: {},
        timeUpdateInterval: null,
        currentTime: 0,
        duration: 0,
        isPlaying: false
    },
    actions: {
        async initMyStreamingPlayer({ commit, state, dispatch }: { commit: Function, state: any, dispatch: Function }) {
            state.player.release();
            state.player = new StreamingPlayer();
            state.options = {
                audioUrl: 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3',
                audioImageUrl: 'https://dummyimage.com/512x512/000000/',
                audioTitle: 'SoundHelix Song 1',
                audioArtist: 'SoundHelix'
            };
            state.player.setMediaSession(state.options, () => dispatch('play'), () => dispatch('pause'), () => dispatch('nextEpisode'), () => dispatch('previousEpisode'));
            await state.player.initPlayer(state.options).then(() => {
                dispatch('updateCurrentTime');
                state.isPlaying = true;
            })
            .catch((error: any) => {
                console.error('Error initializing player: ', error);
            });
        },
        updateCurrentTime({ commit, state, dispatch }: { commit: Function, state: any, dispatch: Function }) {
            state.currentTime = 0;
            state.duration = 0;
            clearInterval(state.timeUpdateInterval);
            state.timeUpdateInterval = setInterval(async () => {
                if (state.duration === 0) {
                    state.duration = Math.round(state.player.duration);
                    if (state.duration > 0) {
                        state.duration = state.duration;
                        state.player.setNowPlayingInfo(state.options, state.currentTime);
                    }
                }
                if (state.currentTime >= 0 && state.currentTime < state.duration) {
                    state.currentTime = Math.round(state.player.currentTime);
                    state.player.updatePlaybackState(state.player.isPlaying, state.currentTime);
                } else {
                    clearInterval(state.timeUpdateInterval);
                }
            }, 1000);
        },
        play({ commit, state, dispatch }: { commit: Function, state: any, dispatch: Function }) {
            if (state.player && !state.player.isPlaying) {
                state.player.play();
                state.isPlaying = true;
                dispatch('updateCurrentTime');
            }
        },
        pause({ commit, state, dispatch }: { commit: Function, state: any, dispatch: Function }) {
            if (state.player && state.player.isPlaying) {
                state.player.pause();
                state.isPlaying = false;
            }
        },
        seekTo({ commit, state, dispatch }: { commit: Function, state: any, dispatch: Function }, time: number) {
            if (state.player && state.player.currentTime && state.player.duration) {
                state.player.seekTo(time);
            }
        },
        nextEpisode({ commit, state, dispatch }: { commit: Function, state: any, dispatch: Function }) {
            // Implement your next episode logic here
        },
        previousEpisode({ commit, state, dispatch }: { commit: Function, state: any, dispatch: Function }) {
            // Implement your previous episode logic here
        },
        forward({ commit, state, dispatch }: { commit: Function, state: any, dispatch: Function }) {
            if (state.player && state.player.currentTime) {
                dispatch('seekTo', state.player.currentTime + 30);
            }
        },
        rewind({ commit, state, dispatch }: { commit: Function, state: any, dispatch: Function }) {
            if (state.player && state.player.currentTime) {
                dispatch('seekTo', state.player.currentTime - 30);
            }
        },
        playPause({ commit, state, dispatch }: { commit: Function, state: any, dispatch: Function }) {
            if (state.player && state.player.isPlaying) {
                dispatch('pause');
            } else {
                dispatch('play');
            }
        }
    },
    getters: {
        isPlaying: (state: State) => state.isPlaying,
        currentTime: (state: State) => state.currentTime,
        duration: (state: State) => state.duration,
        options: (state: State) => state.options
    },
});
// ./components/player.vue
<template>
  <Page>
    <ActionBar title="Streaming Player" />
    <StackLayout>
      <Label :text="audioTitle" class="title" textAlignment="center" />
      <Label :text="`Current Time: ${currentTime} / ${duration}`" textAlignment="center" />
      <GridLayout columns="*, *, *, *, *" rows="auto" class="controls">
        <Button text="Rewind" @tap="rewind" col="0" />
        <Button text="Previous" @tap="previousEpisode" col="1" />
        <Button :text="isPlaying ? 'Pause' : 'Play'" @tap="playPause" col="2" />
        <Button text="Next" @tap="nextEpisode" col="3" />
        <Button text="Forward" @tap="forward" col="4" />
      </GridLayout>
    </StackLayout>
  </Page>
</template>

<script>
import Vue from 'nativescript-vue';
import store from '@/store/audio-streaming';

export default Vue.extend({
  name: 'Player',
  computed: {
    currentTime() {
      return store.getters.currentTime;
    },
    duration() {
      return store.getters.duration;
    },
    isPlaying() {
      return store.getters.isPlaying;
    },
    audioTitle() {
      return store.getters.options.audioTitle;
    },
  },
  async mounted() {
    await store.dispatch('initMyStreamingPlayer');
  },
  methods: {
    playPause() {
      store.dispatch('playPause');
    },
    nextEpisode() {
      store.dispatch('nextEpisode');
    },
    previousEpisode() {
      store.dispatch('previousEpisode');
    },
    forward() {
      store.dispatch('forward');
    },
    rewind() {
      store.dispatch('rewind');
    },
  },
});
</script>

<style scoped>
.title {
  font-size: 18px;
  font-weight: bold;
  margin-top: 20px;
  margin-bottom: 20px;
}

.controls {
  margin-top: 20px;
  gap: 10px;
}

Button {
  padding: 10px;
  font-size: 16px;
}
</style>

License

MIT

1.1.20

9 months ago

1.1.1

10 months ago

1.0.2

10 months ago

1.1.0

10 months ago

1.0.1

10 months ago

1.1.7

10 months ago

1.0.8

10 months ago

1.1.6

10 months ago

1.0.7

10 months ago

1.1.5

10 months ago

1.0.6

10 months ago

1.0.5

10 months ago

1.0.4

10 months ago

1.1.2

10 months ago

1.0.3

10 months ago

1.1.10

10 months ago

1.0.0

10 months ago