react-native-voice-processing
Version:
A fully fledged audio module created for music apps
224 lines (186 loc) • 8.41 kB
JavaScript
import { Platform, AppRegistry, DeviceEventEmitter, NativeEventEmitter, NativeModules } from 'react-native';
import resolveAssetSource from 'react-native/Libraries/Image/resolveAssetSource';
const { VoiceProcessingModule: VoiceProcessing } = NativeModules;
const emitter = Platform.OS !== 'android' ? new NativeEventEmitter(VoiceProcessing) : DeviceEventEmitter;
function resolveAsset(uri) {
if(!uri) return undefined;
return resolveAssetSource(uri);
}
function resolveUrl(url) {
if(!url) return undefined;
return resolveAssetSource(url) || url;
}
function setupPlayer(options) {
return VoiceProcessing.setupPlayer(options || {});
}
function updateOptions(data) {
// Clone the object before modifying it, so we don't run into problems with immutable objects
data = Object.assign({}, data);
// Resolve the asset for each icon
data.icon = resolveAsset(data.icon);
data.playIcon = resolveAsset(data.playIcon);
data.pauseIcon = resolveAsset(data.pauseIcon);
data.stopIcon = resolveAsset(data.stopIcon);
data.previousIcon = resolveAsset(data.previousIcon);
data.nextIcon = resolveAsset(data.nextIcon);
data.rewindIcon = resolveAsset(data.rewindIcon);
data.forwardIcon = resolveAsset(data.forwardIcon);
return VoiceProcessing.updateOptions(data);
}
function add(tracks, insertBeforeId) {
// Clone the array before modifying it, so we don't run into problems with immutable objects
if(Array.isArray(tracks)) {
tracks = [...tracks];
} else {
tracks = [tracks];
}
if(tracks.length < 1) return;
for(let i = 0; i < tracks.length; i++) {
// Clone the object before modifying it
tracks[i] = Object.assign({}, tracks[i]);
// Resolve the URLs
tracks[i].url = resolveUrl(tracks[i].url);
tracks[i].artwork = resolveUrl(tracks[i].artwork);
// Cast ID's into strings
tracks[i].id = `${tracks[i].id}`
}
return VoiceProcessing.add(tracks, insertBeforeId);
}
function remove(tracks) {
if(!Array.isArray(tracks)) {
tracks = [tracks];
}
return VoiceProcessing.remove(tracks);
}
function updateMetadataForTrack(id, metadata) {
// Clone the object before modifying it
metadata = Object.assign({}, metadata);
// Resolve the artowork URL
metadata.artwork = resolveUrl(metadata.artwork);
return VoiceProcessing.updateMetadataForTrack(id, metadata);
}
function registerPlaybackService(serviceFactory) {
if (Platform.OS === 'android') {
// Registers the headless task
AppRegistry.registerHeadlessTask('VoiceProcessing', serviceFactory);
} else {
// Initializes and runs the service in the next tick
setImmediate(serviceFactory());
}
}
function addEventListener(event, listener) {
return emitter.addListener(event, listener);
}
function warpEventResponse(handler, event, payload) {
// transform into the old format and return to handler
const additionalKeys = payload || {};
handler({ type: event, ...additionalKeys });
}
/**
* @deprecated since version 1.0.1. Use addEventListener instead.
*/
function registerEventHandler(handler) {
let events = [
'playback-state',
'playback-error',
'playback-queue-ended',
'playback-track-changed',
'remote-play',
'remote-pause',
'remote-stop',
'remote-next',
'remote-previous',
'remote-jump-forward',
'remote-jump-backward',
'remote-seek',
'remote-duck',
];
if (Platform.OS === 'android') {
events.push('remote-skip', 'remote-set-rating', 'remote-play-id', 'remote-play-search');
}
registerPlaybackService(() => {
return async function() {
for (let i = 0; i < events.length; i++) {
addEventListener(events[i], warpEventResponse.bind(null, handler, events[i]));
}
};
});
}
// We'll declare each one of the constants and functions manually so IDEs can show a list of them
// We should also add documentation here, but I'll leave this task to another day
// States
module.exports.STATE_NONE = VoiceProcessing.STATE_NONE;
module.exports.STATE_READY = VoiceProcessing.STATE_READY;
module.exports.STATE_PLAYING = VoiceProcessing.STATE_PLAYING;
module.exports.STATE_PAUSED = VoiceProcessing.STATE_PAUSED;
module.exports.STATE_STOPPED = VoiceProcessing.STATE_STOPPED;
module.exports.STATE_BUFFERING = VoiceProcessing.STATE_BUFFERING;
module.exports.STATE_CONNECTING = VoiceProcessing.STATE_CONNECTING;
// Capabilities
module.exports.CAPABILITY_PLAY = VoiceProcessing.CAPABILITY_PLAY;
module.exports.CAPABILITY_PLAY_FROM_ID = VoiceProcessing.CAPABILITY_PLAY_FROM_ID;
module.exports.CAPABILITY_PLAY_FROM_SEARCH = VoiceProcessing.CAPABILITY_PLAY_FROM_SEARCH;
module.exports.CAPABILITY_PAUSE = VoiceProcessing.CAPABILITY_PAUSE;
module.exports.CAPABILITY_STOP = VoiceProcessing.CAPABILITY_STOP;
module.exports.CAPABILITY_SEEK_TO = VoiceProcessing.CAPABILITY_SEEK_TO;
module.exports.CAPABILITY_SKIP = VoiceProcessing.CAPABILITY_SKIP;
module.exports.CAPABILITY_SKIP_TO_NEXT = VoiceProcessing.CAPABILITY_SKIP_TO_NEXT;
module.exports.CAPABILITY_SKIP_TO_PREVIOUS = VoiceProcessing.CAPABILITY_SKIP_TO_PREVIOUS;
module.exports.CAPABILITY_JUMP_FORWARD = VoiceProcessing.CAPABILITY_JUMP_FORWARD;
module.exports.CAPABILITY_JUMP_BACKWARD = VoiceProcessing.CAPABILITY_JUMP_BACKWARD;
module.exports.CAPABILITY_SET_RATING = VoiceProcessing.CAPABILITY_SET_RATING;
module.exports.CAPABILITY_LIKE = VoiceProcessing.CAPABILITY_LIKE;
module.exports.CAPABILITY_DISLIKE = VoiceProcessing.CAPABILITY_DISLIKE;
module.exports.CAPABILITY_BOOKMARK = VoiceProcessing.CAPABILITY_BOOKMARK;
// Pitch algorithms
module.exports.PITCH_ALGORITHM_LINEAR = VoiceProcessing.PITCH_ALGORITHM_LINEAR;
module.exports.PITCH_ALGORITHM_MUSIC = VoiceProcessing.PITCH_ALGORITHM_MUSIC;
module.exports.PITCH_ALGORITHM_VOICE = VoiceProcessing.PITCH_ALGORITHM_VOICE;
// Rating Types
module.exports.RATING_HEART = VoiceProcessing.RATING_HEART;
module.exports.RATING_THUMBS_UP_DOWN = VoiceProcessing.RATING_THUMBS_UP_DOWN;
module.exports.RATING_3_STARS = VoiceProcessing.RATING_3_STARS;
module.exports.RATING_4_STARS = VoiceProcessing.RATING_4_STARS;
module.exports.RATING_5_STARS = VoiceProcessing.RATING_5_STARS;
module.exports.RATING_PERCENTAGE = VoiceProcessing.RATING_PERCENTAGE;
// General
module.exports.setupPlayer = setupPlayer;
module.exports.destroy = VoiceProcessing.destroy;
module.exports.updateOptions = updateOptions;
module.exports.registerEventHandler = registerEventHandler;
module.exports.registerBackendService = registerPlaybackService;
module.exports.registerPlaybackService = registerPlaybackService;
module.exports.addEventListener = addEventListener;
// Player Queue Commands
module.exports.add = add;
module.exports.remove = remove;
module.exports.skip = VoiceProcessing.skip;
module.exports.getQueue = VoiceProcessing.getQueue;
module.exports.skipToNext = VoiceProcessing.skipToNext;
module.exports.skipToPrevious = VoiceProcessing.skipToPrevious;
module.exports.updateMetadataForTrack = updateMetadataForTrack;
module.exports.removeUpcomingTracks = VoiceProcessing.removeUpcomingTracks;
// Player Playback Commands
module.exports.reset = VoiceProcessing.reset;
module.exports.play = VoiceProcessing.play;
module.exports.pause = VoiceProcessing.pause;
module.exports.stop = VoiceProcessing.stop;
module.exports.seekTo = VoiceProcessing.seekTo;
module.exports.setVolume = VoiceProcessing.setVolume;
module.exports.setRate = VoiceProcessing.setRate;
// Player Getters
module.exports.getTrack = VoiceProcessing.getTrack;
module.exports.getCurrentTrack = VoiceProcessing.getCurrentTrack;
module.exports.getVolume = VoiceProcessing.getVolume;
module.exports.getDuration = VoiceProcessing.getDuration;
module.exports.getPosition = VoiceProcessing.getPosition;
module.exports.getBufferedPosition = VoiceProcessing.getBufferedPosition;
module.exports.getState = VoiceProcessing.getState;
module.exports.getRate = VoiceProcessing.getRate;
// Player Event Types
module.exports.VoiceProcessingEvents = require('./eventTypes');
// Components
module.exports.ProgressComponent = require('./ProgressComponent');
// React Hooks (Requires React v16.8+ and React Native v0.59+)
const hooks = require('./hooks');
module.exports = { ...module.exports, ...hooks }