Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@cycle-robot-drivers/sound

Package Overview
Dependencies
Maintainers
1
Versions
14
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@cycle-robot-drivers/sound - npm Package Compare versions

Comparing version 0.0.8 to 1.0.1

18

lib/cjs/AudioPlayerAction.d.ts

@@ -1,8 +0,7 @@

import { ActionSinks } from '@cycle-robot-drivers/action';
export interface Sources {
goal: any;
AudioPlayer: any;
import { ActionSources, ActionSinks, EventSource } from '@cycle-robot-drivers/action';
export interface Sources extends ActionSources {
AudioPlayer: EventSource;
}
export interface Sinks extends ActionSinks {
output: any;
AudioPlayer: any;
}

@@ -14,3 +13,3 @@ /**

*
* * goal: a stream of `null` (as "cancel") or `{src: string}` (as HTML audio
* * goal: a stream of `{src: string}` (as HTML audio
* [src](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/audio#attr-src))

@@ -22,7 +21,8 @@ * or a string (as a value of `src`).

*
* * output: a stream for the AudioPlayer driver.
* * status: depreciated.
* * result: a stream of action results. `result.result` is always `null`.
* * state: a reducer stream.
* * status: a stream of action status.
* * result: a stream of action results.
* * AudioPlayer: a stream for `AudioPlayer` driver input.
*
*/
export declare function AudioPlayerAction(sources: Sources): Sinks;
"use strict";
var __assign = (this && this.__assign) || Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};

@@ -16,4 +19,131 @@ var __importDefault = (this && this.__importDefault) || function (mod) {

var dropRepeats_1 = __importDefault(require("xstream/extra/dropRepeats"));
var adapt_1 = require("@cycle/run/lib/adapt");
var action_1 = require("@cycle-robot-drivers/action");
var State;
(function (State) {
State["WAIT"] = "WAIT";
State["RUN"] = "RUN";
State["PREEMPT"] = "PREEMPT";
})(State || (State = {}));
var InputType;
(function (InputType) {
InputType["GOAL"] = "GOAL";
InputType["CANCEL"] = "CANCEL";
InputType["ENDED"] = "ENDED";
InputType["PAUSE"] = "PAUSE";
})(InputType || (InputType = {}));
function input(goal$, cancel$, audioPlayerEndedEvent$, audioPlayerPausedEvent$) {
return xstream_1.default.merge(goal$.filter(function (g) { return typeof g !== 'undefined' && g !== null; })
.map(function (g) { return action_1.initGoal(g); })
.map(function (goal) { return ({
type: InputType.GOAL,
value: typeof goal.goal === 'string' ? {
goal_id: goal.goal_id,
goal: { src: goal.goal },
} : goal,
}); }), cancel$.map(function (val) { return ({ type: InputType.CANCEL, value: val }); }), audioPlayerEndedEvent$.mapTo({
type: InputType.ENDED,
value: null,
}), audioPlayerPausedEvent$.mapTo({
type: InputType.PAUSE,
value: null,
}));
}
function transition(prev, input) {
if (prev.state === State.WAIT) {
if (input.type === InputType.GOAL) {
var goal = input.value;
return __assign({}, prev, { state: State.RUN, variables: {
goal_id: goal.goal_id,
newGoal: null,
}, outputs: {
AudioPlayer: goal.goal,
} });
}
}
else if (prev.state === State.RUN) {
if (input.type === InputType.GOAL || input.type === InputType.CANCEL
&& (input.value === null ||
action_1.isEqualGoalID(input.value, prev.variables.goal_id))) {
return __assign({}, prev, { state: State.PREEMPT, variables: __assign({}, prev.variables, { newGoal: input.type === InputType.GOAL ? input.value : null }), outputs: {
AudioPlayer: null,
} });
}
else if (input.type === InputType.ENDED) {
return __assign({}, prev, { state: State.WAIT, variables: {
goal_id: null,
newGoal: null,
}, outputs: {
result: {
status: {
goal_id: prev.variables.goal_id,
status: action_1.Status.SUCCEEDED,
},
result: input.value,
},
} });
}
}
else if (prev.state === State.PREEMPT) {
if (input.type === InputType.ENDED || input.type === InputType.PAUSE) {
var newGoal = prev.variables.newGoal;
return __assign({}, prev, { state: !!newGoal ? State.RUN : State.WAIT, variables: {
goal_id: !!newGoal ? newGoal.goal_id : null,
newGoal: null,
}, outputs: {
AudioPlayer: !!newGoal ? newGoal.goal : undefined,
result: {
status: {
goal_id: prev.variables.goal_id,
status: action_1.Status.PREEMPTED,
},
result: input.value,
},
} });
}
}
return prev;
}
function transitionReducer(input$) {
var initReducer$ = xstream_1.default.of(function initReducer(prev) {
return {
state: State.WAIT,
variables: {
goal_id: null,
newGoal: null,
},
outputs: null,
};
});
var inputReducer$ = input$
.map(function (input) { return function inputReducer(prev) {
return transition(prev, input);
}; });
return xstream_1.default.merge(initReducer$, inputReducer$);
}
function status(reducerState$) {
var done$ = reducerState$
.filter(function (rs) { return !!rs.outputs && !!rs.outputs.result; })
.map(function (rs) { return rs.outputs.result.status; });
var active$ = reducerState$
.filter(function (rs) { return rs.state === State.RUN; })
.map(function (rs) { return ({ goal_id: rs.variables.goal_id, status: action_1.Status.ACTIVE }); });
var initGoalStatus = action_1.generateGoalStatus({ status: action_1.Status.SUCCEEDED });
return xstream_1.default.merge(done$, active$)
.compose(dropRepeats_1.default(action_1.isEqualGoalStatus))
.startWith(initGoalStatus);
}
function output(reducerState$) {
var outputs$ = reducerState$
.filter(function (rs) { return !!rs.outputs; })
.map(function (rs) { return rs.outputs; });
return {
result: outputs$
.filter(function (o) { return !!o.result; })
.map(function (o) { return o.result; }),
AudioPlayer: outputs$
.filter(function (o) { return typeof o.AudioPlayer !== 'undefined'; })
.map(function (o) { return o.AudioPlayer; }),
};
}
;
/**

@@ -24,3 +154,3 @@ * AudioPlayerAction action component.

*
* * goal: a stream of `null` (as "cancel") or `{src: string}` (as HTML audio
* * goal: a stream of `{src: string}` (as HTML audio
* [src](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/audio#attr-src))

@@ -32,131 +162,17 @@ * or a string (as a value of `src`).

*
* * output: a stream for the AudioPlayer driver.
* * status: depreciated.
* * result: a stream of action results. `result.result` is always `null`.
* * state: a reducer stream.
* * status: a stream of action status.
* * result: a stream of action results.
* * AudioPlayer: a stream for `AudioPlayer` driver input.
*
*/
function AudioPlayerAction(sources) {
var goal$ = xstream_1.default.fromObservable(sources.goal).filter(function (goal) { return typeof goal !== 'undefined'; }).map(function (goal) {
if (goal === null) {
return {
type: 'CANCEL',
value: null,
};
}
else {
var value = !!goal.goal_id ? goal : action_1.initGoal(goal);
return {
type: 'GOAL',
value: typeof value.goal === 'string'
? {
goal_id: value.goal_id,
goal: { src: value.goal },
} : value,
};
}
});
var events$ = xstream_1.default.merge(sources.AudioPlayer.events('ended').map(function (event) { return ({ type: 'ENDED', value: event }); }), sources.AudioPlayer.events('pause').map(function (event) { return ({ type: 'PAUSE', value: event }); }));
var action$ = xstream_1.default.merge(goal$, events$);
// Create state stream
var ExtraStatus;
(function (ExtraStatus) {
ExtraStatus["PREEMPTING"] = "PREEMPTING";
})(ExtraStatus || (ExtraStatus = {}));
var input$ = input(sources.goal, sources.cancel || xstream_1.default.never(), sources.AudioPlayer.events('ended'), sources.AudioPlayer.events('pause'));
var reducer = transitionReducer(input$);
;
var initialState = {
goal: null,
goal_id: action_1.generateGoalID(),
status: action_1.Status.SUCCEEDED,
result: null,
newGoal: null,
};
var state$ = action$.fold(function (state, action) {
// console.debug('state', state, 'action', action);
if (state.status === action_1.Status.SUCCEEDED
|| state.status === action_1.Status.PREEMPTED
|| state.status === action_1.Status.ABORTED) {
if (action.type === 'GOAL') {
return {
goal_id: action.value.goal_id,
goal: action.value.goal,
status: action_1.Status.ACTIVE,
result: null,
newGoal: null,
};
}
else if (action.type === 'CANCEL') {
console.debug('Ignore CANCEL in DONE states');
return state;
}
}
else if (state.status === action_1.Status.ACTIVE) {
if (action.type === 'GOAL') {
return __assign({}, state, { goal: null, status: ExtraStatus.PREEMPTING, newGoal: action.value });
}
else if (action.type === 'ENDED') {
return __assign({}, state, { status: action_1.Status.SUCCEEDED, result: null });
}
else if (action.type === 'CANCEL') {
return __assign({}, state, { goal: null, status: ExtraStatus.PREEMPTING });
}
else if (action.type === 'PAUSE') {
console.debug('Ignore pause in ACTIVE states; used ENDED instead');
return state;
}
}
else if (state.status === ExtraStatus.PREEMPTING) {
if (action.type === 'ENDED' || action.type === 'PAUSE') {
var preemptedState = __assign({}, state, { status: action_1.Status.PREEMPTED, newGoal: null });
if (state.newGoal) {
state$.shamefullySendNext(preemptedState);
return {
goal_id: state.newGoal.goal_id,
goal: state.newGoal.goal,
status: action_1.Status.ACTIVE,
result: null,
newGoal: null,
};
}
else {
return preemptedState;
}
}
}
console.debug("Unhandled state.status " + state.status + " action.type " + action.type);
return state;
}, initialState);
// Prepare outgoing streams
var stateStatusChanged$ = state$
.compose(dropRepeats_1.default(function (x, y) { return (x.status === y.status && action_1.isEqual(x.goal_id, y.goal_id)); }));
var value$ = stateStatusChanged$
.filter(function (state) { return (state.status === action_1.Status.ACTIVE
|| state.status === ExtraStatus.PREEMPTING); })
.map(function (state) { return state.goal; });
var status$ = stateStatusChanged$
.filter(function (state) { return state.status !== ExtraStatus.PREEMPTING; })
.map(function (state) { return ({
goal_id: state.goal_id,
status: state.status,
}); });
var result$ = stateStatusChanged$
.filter(function (state) { return (state.status === action_1.Status.SUCCEEDED
|| state.status === action_1.Status.PREEMPTED
|| state.status === action_1.Status.ABORTED); })
.map(function (state) { return ({
status: {
goal_id: state.goal_id,
status: state.status,
},
result: state.result,
}); });
// IMPORTANT!! empty the streams manually; otherwise it emits the first
// "SUCCEEDED" result
value$.addListener({ next: function () { } });
return {
output: adapt_1.adapt(value$),
status: adapt_1.adapt(status$),
result: adapt_1.adapt(result$),
};
var status$ = status(sources.state.stream);
var outputs = output(sources.state.stream);
return __assign({ state: reducer, status: status$ }, outputs);
}
exports.AudioPlayerAction = AudioPlayerAction;
//# sourceMappingURL=AudioPlayerAction.js.map
export { makeAudioPlayerDriver } from './makeAudioPlayerDriver';
export { Sources as AudioPlayerActionSources, Sinks as AudioPlayerActionSinks, AudioPlayerAction } from './AudioPlayerAction';
export { Sources as AudioPlayerActionSources, Sinks as AudioPlayerActionSinks, AudioPlayerAction, } from './AudioPlayerAction';

@@ -6,2 +6,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
var xstream_1 = __importDefault(require("xstream"));
var fromEvent_1 = __importDefault(require("xstream/extra/fromEvent"));

@@ -32,3 +33,3 @@ var adapt_1 = require("@cycle/run/lib/adapt");

return function audioPlayerDriver(sink$) {
sink$.addListener({
xstream_1.default.fromObservable(sink$).addListener({
next: function (args) {

@@ -35,0 +36,0 @@ if (!args) {

@@ -1,8 +0,7 @@

import { ActionSinks } from '@cycle-robot-drivers/action';
export interface Sources {
goal: any;
AudioPlayer: any;
import { ActionSources, ActionSinks, EventSource } from '@cycle-robot-drivers/action';
export interface Sources extends ActionSources {
AudioPlayer: EventSource;
}
export interface Sinks extends ActionSinks {
output: any;
AudioPlayer: any;
}

@@ -14,3 +13,3 @@ /**

*
* * goal: a stream of `null` (as "cancel") or `{src: string}` (as HTML audio
* * goal: a stream of `{src: string}` (as HTML audio
* [src](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/audio#attr-src))

@@ -22,7 +21,8 @@ * or a string (as a value of `src`).

*
* * output: a stream for the AudioPlayer driver.
* * status: depreciated.
* * result: a stream of action results. `result.result` is always `null`.
* * state: a reducer stream.
* * status: a stream of action status.
* * result: a stream of action results.
* * AudioPlayer: a stream for `AudioPlayer` driver input.
*
*/
export declare function AudioPlayerAction(sources: Sources): Sinks;

@@ -1,13 +0,143 @@

var __assign = (this && this.__assign) || Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
import xs from 'xstream';
import dropRepeats from 'xstream/extra/dropRepeats';
import { adapt } from '@cycle/run/lib/adapt';
import { Status, initGoal, generateGoalID, isEqual, } from '@cycle-robot-drivers/action';
import { Status, initGoal, generateGoalStatus, isEqualGoalStatus, isEqualGoalID, } from '@cycle-robot-drivers/action';
var State;
(function (State) {
State["WAIT"] = "WAIT";
State["RUN"] = "RUN";
State["PREEMPT"] = "PREEMPT";
})(State || (State = {}));
var InputType;
(function (InputType) {
InputType["GOAL"] = "GOAL";
InputType["CANCEL"] = "CANCEL";
InputType["ENDED"] = "ENDED";
InputType["PAUSE"] = "PAUSE";
})(InputType || (InputType = {}));
function input(goal$, cancel$, audioPlayerEndedEvent$, audioPlayerPausedEvent$) {
return xs.merge(goal$.filter(function (g) { return typeof g !== 'undefined' && g !== null; })
.map(function (g) { return initGoal(g); })
.map(function (goal) { return ({
type: InputType.GOAL,
value: typeof goal.goal === 'string' ? {
goal_id: goal.goal_id,
goal: { src: goal.goal },
} : goal,
}); }), cancel$.map(function (val) { return ({ type: InputType.CANCEL, value: val }); }), audioPlayerEndedEvent$.mapTo({
type: InputType.ENDED,
value: null,
}), audioPlayerPausedEvent$.mapTo({
type: InputType.PAUSE,
value: null,
}));
}
function transition(prev, input) {
if (prev.state === State.WAIT) {
if (input.type === InputType.GOAL) {
var goal = input.value;
return __assign({}, prev, { state: State.RUN, variables: {
goal_id: goal.goal_id,
newGoal: null,
}, outputs: {
AudioPlayer: goal.goal,
} });
}
}
else if (prev.state === State.RUN) {
if (input.type === InputType.GOAL || input.type === InputType.CANCEL
&& (input.value === null ||
isEqualGoalID(input.value, prev.variables.goal_id))) {
return __assign({}, prev, { state: State.PREEMPT, variables: __assign({}, prev.variables, { newGoal: input.type === InputType.GOAL ? input.value : null }), outputs: {
AudioPlayer: null,
} });
}
else if (input.type === InputType.ENDED) {
return __assign({}, prev, { state: State.WAIT, variables: {
goal_id: null,
newGoal: null,
}, outputs: {
result: {
status: {
goal_id: prev.variables.goal_id,
status: Status.SUCCEEDED,
},
result: input.value,
},
} });
}
}
else if (prev.state === State.PREEMPT) {
if (input.type === InputType.ENDED || input.type === InputType.PAUSE) {
var newGoal = prev.variables.newGoal;
return __assign({}, prev, { state: !!newGoal ? State.RUN : State.WAIT, variables: {
goal_id: !!newGoal ? newGoal.goal_id : null,
newGoal: null,
}, outputs: {
AudioPlayer: !!newGoal ? newGoal.goal : undefined,
result: {
status: {
goal_id: prev.variables.goal_id,
status: Status.PREEMPTED,
},
result: input.value,
},
} });
}
}
return prev;
}
function transitionReducer(input$) {
var initReducer$ = xs.of(function initReducer(prev) {
return {
state: State.WAIT,
variables: {
goal_id: null,
newGoal: null,
},
outputs: null,
};
});
var inputReducer$ = input$
.map(function (input) { return function inputReducer(prev) {
return transition(prev, input);
}; });
return xs.merge(initReducer$, inputReducer$);
}
function status(reducerState$) {
var done$ = reducerState$
.filter(function (rs) { return !!rs.outputs && !!rs.outputs.result; })
.map(function (rs) { return rs.outputs.result.status; });
var active$ = reducerState$
.filter(function (rs) { return rs.state === State.RUN; })
.map(function (rs) { return ({ goal_id: rs.variables.goal_id, status: Status.ACTIVE }); });
var initGoalStatus = generateGoalStatus({ status: Status.SUCCEEDED });
return xs.merge(done$, active$)
.compose(dropRepeats(isEqualGoalStatus))
.startWith(initGoalStatus);
}
function output(reducerState$) {
var outputs$ = reducerState$
.filter(function (rs) { return !!rs.outputs; })
.map(function (rs) { return rs.outputs; });
return {
result: outputs$
.filter(function (o) { return !!o.result; })
.map(function (o) { return o.result; }),
AudioPlayer: outputs$
.filter(function (o) { return typeof o.AudioPlayer !== 'undefined'; })
.map(function (o) { return o.AudioPlayer; }),
};
}
;
/**

@@ -18,3 +148,3 @@ * AudioPlayerAction action component.

*
* * goal: a stream of `null` (as "cancel") or `{src: string}` (as HTML audio
* * goal: a stream of `{src: string}` (as HTML audio
* [src](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/audio#attr-src))

@@ -26,130 +156,16 @@ * or a string (as a value of `src`).

*
* * output: a stream for the AudioPlayer driver.
* * status: depreciated.
* * result: a stream of action results. `result.result` is always `null`.
* * state: a reducer stream.
* * status: a stream of action status.
* * result: a stream of action results.
* * AudioPlayer: a stream for `AudioPlayer` driver input.
*
*/
export function AudioPlayerAction(sources) {
var goal$ = xs.fromObservable(sources.goal).filter(function (goal) { return typeof goal !== 'undefined'; }).map(function (goal) {
if (goal === null) {
return {
type: 'CANCEL',
value: null,
};
}
else {
var value = !!goal.goal_id ? goal : initGoal(goal);
return {
type: 'GOAL',
value: typeof value.goal === 'string'
? {
goal_id: value.goal_id,
goal: { src: value.goal },
} : value,
};
}
});
var events$ = xs.merge(sources.AudioPlayer.events('ended').map(function (event) { return ({ type: 'ENDED', value: event }); }), sources.AudioPlayer.events('pause').map(function (event) { return ({ type: 'PAUSE', value: event }); }));
var action$ = xs.merge(goal$, events$);
// Create state stream
var ExtraStatus;
(function (ExtraStatus) {
ExtraStatus["PREEMPTING"] = "PREEMPTING";
})(ExtraStatus || (ExtraStatus = {}));
var input$ = input(sources.goal, sources.cancel || xs.never(), sources.AudioPlayer.events('ended'), sources.AudioPlayer.events('pause'));
var reducer = transitionReducer(input$);
;
var initialState = {
goal: null,
goal_id: generateGoalID(),
status: Status.SUCCEEDED,
result: null,
newGoal: null,
};
var state$ = action$.fold(function (state, action) {
// console.debug('state', state, 'action', action);
if (state.status === Status.SUCCEEDED
|| state.status === Status.PREEMPTED
|| state.status === Status.ABORTED) {
if (action.type === 'GOAL') {
return {
goal_id: action.value.goal_id,
goal: action.value.goal,
status: Status.ACTIVE,
result: null,
newGoal: null,
};
}
else if (action.type === 'CANCEL') {
console.debug('Ignore CANCEL in DONE states');
return state;
}
}
else if (state.status === Status.ACTIVE) {
if (action.type === 'GOAL') {
return __assign({}, state, { goal: null, status: ExtraStatus.PREEMPTING, newGoal: action.value });
}
else if (action.type === 'ENDED') {
return __assign({}, state, { status: Status.SUCCEEDED, result: null });
}
else if (action.type === 'CANCEL') {
return __assign({}, state, { goal: null, status: ExtraStatus.PREEMPTING });
}
else if (action.type === 'PAUSE') {
console.debug('Ignore pause in ACTIVE states; used ENDED instead');
return state;
}
}
else if (state.status === ExtraStatus.PREEMPTING) {
if (action.type === 'ENDED' || action.type === 'PAUSE') {
var preemptedState = __assign({}, state, { status: Status.PREEMPTED, newGoal: null });
if (state.newGoal) {
state$.shamefullySendNext(preemptedState);
return {
goal_id: state.newGoal.goal_id,
goal: state.newGoal.goal,
status: Status.ACTIVE,
result: null,
newGoal: null,
};
}
else {
return preemptedState;
}
}
}
console.debug("Unhandled state.status " + state.status + " action.type " + action.type);
return state;
}, initialState);
// Prepare outgoing streams
var stateStatusChanged$ = state$
.compose(dropRepeats(function (x, y) { return (x.status === y.status && isEqual(x.goal_id, y.goal_id)); }));
var value$ = stateStatusChanged$
.filter(function (state) { return (state.status === Status.ACTIVE
|| state.status === ExtraStatus.PREEMPTING); })
.map(function (state) { return state.goal; });
var status$ = stateStatusChanged$
.filter(function (state) { return state.status !== ExtraStatus.PREEMPTING; })
.map(function (state) { return ({
goal_id: state.goal_id,
status: state.status,
}); });
var result$ = stateStatusChanged$
.filter(function (state) { return (state.status === Status.SUCCEEDED
|| state.status === Status.PREEMPTED
|| state.status === Status.ABORTED); })
.map(function (state) { return ({
status: {
goal_id: state.goal_id,
status: state.status,
},
result: state.result,
}); });
// IMPORTANT!! empty the streams manually; otherwise it emits the first
// "SUCCEEDED" result
value$.addListener({ next: function () { } });
return {
output: adapt(value$),
status: adapt(status$),
result: adapt(result$),
};
var status$ = status(sources.state.stream);
var outputs = output(sources.state.stream);
return __assign({ state: reducer, status: status$ }, outputs);
}
//# sourceMappingURL=AudioPlayerAction.js.map
export { makeAudioPlayerDriver } from './makeAudioPlayerDriver';
export { Sources as AudioPlayerActionSources, Sinks as AudioPlayerActionSinks, AudioPlayerAction } from './AudioPlayerAction';
export { Sources as AudioPlayerActionSources, Sinks as AudioPlayerActionSinks, AudioPlayerAction, } from './AudioPlayerAction';

@@ -0,1 +1,2 @@

import xs from 'xstream';
import fromEvent from 'xstream/extra/fromEvent';

@@ -26,3 +27,3 @@ import { adapt } from '@cycle/run/lib/adapt';

return function audioPlayerDriver(sink$) {
sink$.addListener({
xs.fromObservable(sink$).addListener({
next: function (args) {

@@ -29,0 +30,0 @@ if (!args) {

{
"name": "@cycle-robot-drivers/sound",
"version": "0.0.8",
"description": "",
"version": "1.0.1",
"description": "A Cycle.js driver for playing sounds using HTMLAudioElement",
"author": "Michael Jae-Yoon Chung",

@@ -13,9 +13,10 @@ "license": "MIT",

"dependencies": {
"@cycle/run": "5.1.0",
"@cycle-robot-drivers/action": "~0.0.0",
"xstream": "11.7.0"
"@cycle-robot-drivers/action": "^1.0.0",
"@cycle/run": "5.2.0",
"xstream": "11.10.0"
},
"devDependencies": {
"@cycle/time": "^0.15.0",
"@types/node": "^10.5.7"
"@cycle/state": "^1.2.0",
"@cycle/time": "^0.19.0",
"@types/node": "^11.9.4"
},

@@ -22,0 +23,0 @@ "scripts": {

@@ -22,3 +22,3 @@ <!-- This README.md is automatically generated. Edit the JSDoc comments in source code or the md files in docs/readmes/. -->

* *sources*
* goal: a stream of `null` (as "cancel") or `{src: string}` (as HTML audio
* goal: a stream of `{src: string}` (as HTML audio
[src](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/audio#attr-src))

@@ -31,5 +31,6 @@ or a string (as a value of `src`).

* sinks
* output: a stream for the AudioPlayer driver.
* status: depreciated.
* result: a stream of action results. `result.result` is always `null`.
* state: a reducer stream.
* status: a stream of action status.
* result: a stream of action results.
* AudioPlayer: a stream for `AudioPlayer` driver input.

@@ -36,0 +37,0 @@ <!-- End src/AudioPlayerAction.ts -->

@@ -1,201 +0,241 @@

import xs from 'xstream';
import xs, {Stream} from 'xstream';
import dropRepeats from 'xstream/extra/dropRepeats';
import {adapt} from '@cycle/run/lib/adapt';
import {
GoalID, Goal, GoalStatus, Status, Result, ActionSinks,
initGoal, generateGoalID, isEqual,
} from '@cycle-robot-drivers/action'
GoalID, Goal, GoalStatus, Status, Result,
ActionSources, ActionSinks,
EventSource,
initGoal, generateGoalStatus, isEqualGoalStatus, isEqualGoalID,
} from '@cycle-robot-drivers/action';
export interface Sources {
goal: any,
AudioPlayer: any,
enum State {
WAIT = 'WAIT',
RUN = 'RUN',
PREEMPT = 'PREEMPT',
}
export interface Sinks extends ActionSinks {
output: any,
type Variables = {
goal_id: GoalID,
newGoal: Goal,
};
type Outputs = {
AudioPlayer?: any,
result?: Result,
};
type ReducerState = {
state: State,
variables: Variables,
outputs: Outputs,
};
type Reducer = (prev?: ReducerState) => ReducerState | undefined;
enum InputType {
GOAL = 'GOAL',
CANCEL = 'CANCEL',
ENDED = 'ENDED',
PAUSE = 'PAUSE',
}
type Input = {
type: InputType,
value: Goal | GoalID | string,
};
/**
* AudioPlayerAction action component.
*
* @param sources
*
* * goal: a stream of `null` (as "cancel") or `{src: string}` (as HTML audio
* [src](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/audio#attr-src))
* or a string (as a value of `src`).
* * AudioPlayer: `EventSource` for `ended` and `pause` events.
*
* @return sinks
*
* * output: a stream for the AudioPlayer driver.
* * status: depreciated.
* * result: a stream of action results. `result.result` is always `null`.
*
*/
export function AudioPlayerAction(sources: Sources): Sinks {
// Create action stream
type Action = {
type: string,
value: Goal | string,
};
const goal$ = xs.fromObservable(
sources.goal
).filter(goal => typeof goal !== 'undefined').map(goal => {
if (goal === null) {
function input(
goal$: Stream<Goal | string>,
cancel$: Stream<GoalID>,
audioPlayerEndedEvent$: Stream<GoalID>,
audioPlayerPausedEvent$: Stream<GoalID>,
): Stream<Input> {
return xs.merge(
goal$.filter(g => typeof g !== 'undefined' && g !== null)
.map(g => initGoal(g))
.map(goal => ({
type: InputType.GOAL,
value: typeof goal.goal === 'string' ? {
goal_id: goal.goal_id,
goal: {src: goal.goal},
} : goal,
})),
cancel$.map(val => ({type: InputType.CANCEL, value: val})),
audioPlayerEndedEvent$.mapTo({
type: InputType.ENDED,
value: null,
}),
audioPlayerPausedEvent$.mapTo({
type: InputType.PAUSE,
value: null,
}),
);
}
function transition(prev: ReducerState, input: Input): ReducerState {
if (prev.state === State.WAIT) {
if (input.type === InputType.GOAL) {
const goal = (input.value as Goal);
return {
type: 'CANCEL',
value: null, // goal MUST BE null on CANCEL
...prev,
state: State.RUN,
variables: {
goal_id: goal.goal_id,
newGoal: null,
},
outputs: {
AudioPlayer: goal.goal,
},
};
} else {
const value = !!(goal as any).goal_id ? goal as any : initGoal(goal);
}
} else if (prev.state === State.RUN) {
if (input.type === InputType.GOAL || input.type === InputType.CANCEL
&& (input.value === null ||
isEqualGoalID(input.value as GoalID, prev.variables.goal_id))) {
return {
type: 'GOAL',
value: typeof value.goal === 'string'
? {
goal_id: value.goal_id,
goal: {src: value.goal},
} : value,
...prev,
state: State.PREEMPT,
variables: {
...prev.variables,
newGoal: input.type === InputType.GOAL ? (input.value as Goal) : null,
},
outputs: {
AudioPlayer: null,
},
};
} else if (input.type === InputType.ENDED) {
return {
...prev,
state: State.WAIT,
variables: {
goal_id: null,
newGoal: null,
},
outputs: {
result: {
status: {
goal_id: prev.variables.goal_id,
status: Status.SUCCEEDED,
},
result: input.value,
},
},
};
}
});
const events$ = xs.merge(
sources.AudioPlayer.events('ended').map(
event => ({type: 'ENDED', value: event})
),
sources.AudioPlayer.events('pause').map(
event => ({type: 'PAUSE', value: event})
),
);
const action$ = xs.merge(goal$, events$);
} else if (prev.state === State.PREEMPT) {
if (input.type === InputType.ENDED || input.type === InputType.PAUSE) {
const newGoal = prev.variables.newGoal;
return {
...prev,
state: !!newGoal ? State.RUN : State.WAIT,
variables: {
goal_id: !!newGoal ? newGoal.goal_id : null,
newGoal: null,
},
outputs: {
AudioPlayer: !!newGoal ? newGoal.goal : undefined,
result: {
status: {
goal_id: prev.variables.goal_id,
status: Status.PREEMPTED,
},
result: input.value,
},
},
};
}
}
return prev;
}
// Create state stream
enum ExtraStatus {
PREEMPTING = 'PREEMPTING',
};
type ExtendedStatus = Status | ExtraStatus;
type State = {
goal_id: GoalID,
goal: any,
status: ExtendedStatus,
result: any,
newGoal: Goal,
};
const initialState: State = {
goal: null,
goal_id: generateGoalID(),
status: Status.SUCCEEDED,
result: null,
newGoal: null,
};
const state$ = action$.fold((state: State, action: Action): State => {
// console.debug('state', state, 'action', action);
if (state.status === Status.SUCCEEDED
|| state.status === Status.PREEMPTED
|| state.status === Status.ABORTED) {
if (action.type === 'GOAL') {
return {
goal_id: (action.value as Goal).goal_id,
goal: (action.value as Goal).goal,
status: Status.ACTIVE,
result: null,
function transitionReducer(input$: Stream<Input>): Stream<Reducer> {
const initReducer$: Stream<Reducer> = xs.of(
function initReducer(prev: ReducerState): ReducerState {
return {
state: State.WAIT,
variables: {
goal_id: null,
newGoal: null,
};
} else if (action.type === 'CANCEL') {
console.debug('Ignore CANCEL in DONE states');
return state;
},
outputs: null,
}
} else if (state.status === Status.ACTIVE) {
if (action.type === 'GOAL') {
return {
...state,
goal: null,
status: ExtraStatus.PREEMPTING,
newGoal: (action.value as Goal)
}
} else if (action.type === 'ENDED') {
return {
...state,
status: Status.SUCCEEDED,
result: null,
}
} else if (action.type === 'CANCEL') {
return {
...state,
goal: null,
status: ExtraStatus.PREEMPTING,
}
} else if (action.type === 'PAUSE') {
console.debug('Ignore pause in ACTIVE states; used ENDED instead');
return state;
}
} else if (state.status === ExtraStatus.PREEMPTING) {
if (action.type === 'ENDED' || action.type === 'PAUSE') {
const preemptedState = {
...state,
status: Status.PREEMPTED,
newGoal: null,
};
if (state.newGoal) {
state$.shamefullySendNext(preemptedState);
return {
goal_id: state.newGoal.goal_id,
goal: state.newGoal.goal,
status: Status.ACTIVE,
result: null,
newGoal: null,
};
} else {
return preemptedState;
}
}
}
console.debug(
`Unhandled state.status ${state.status} action.type ${action.type}`
);
return state;
}, initialState);
);
const inputReducer$: Stream<Reducer> = input$
.map(input => function inputReducer(prev: ReducerState): ReducerState {
return transition(prev, input);
});
// Prepare outgoing streams
const stateStatusChanged$ = state$
.compose(dropRepeats(
(x, y) => (x.status === y.status && isEqual(x.goal_id, y.goal_id))));
return xs.merge(initReducer$, inputReducer$);
}
const value$ = stateStatusChanged$
.filter(state => (state.status === Status.ACTIVE
|| state.status === ExtraStatus.PREEMPTING))
.map(state => state.goal);
const status$ = stateStatusChanged$
.filter(state => state.status !== ExtraStatus.PREEMPTING)
.map(state => ({
goal_id: state.goal_id,
status: state.status,
} as GoalStatus));
const result$ = stateStatusChanged$
.filter(state => (state.status === Status.SUCCEEDED
|| state.status === Status.PREEMPTED
|| state.status === Status.ABORTED))
.map(state => ({
status: {
goal_id: state.goal_id,
status: state.status,
},
result: state.result,
} as Result));
function status(reducerState$): Stream<GoalStatus> {
const done$: Stream<GoalStatus> = reducerState$
.filter(rs => !!rs.outputs && !!rs.outputs.result)
.map(rs => rs.outputs.result.status);
const active$: Stream<GoalStatus> = reducerState$
.filter(rs => rs.state === State.RUN)
.map(rs => ({goal_id: rs.variables.goal_id, status: Status.ACTIVE}));
const initGoalStatus = generateGoalStatus({status: Status.SUCCEEDED});
return xs.merge(done$, active$)
.compose(dropRepeats(isEqualGoalStatus))
.startWith(initGoalStatus);
}
// IMPORTANT!! empty the streams manually; otherwise it emits the first
// "SUCCEEDED" result
value$.addListener({next: () => {}});
function output(reducerState$) {
const outputs$ = reducerState$
.filter(rs => !!rs.outputs)
.map(rs => rs.outputs);
return {
result: outputs$
.filter(o => !!o.result)
.map(o => o.result),
AudioPlayer: outputs$
.filter(o => typeof o.AudioPlayer !== 'undefined')
.map(o => o.AudioPlayer),
};
};
export interface Sources extends ActionSources {
AudioPlayer: EventSource,
}
export interface Sinks extends ActionSinks {
AudioPlayer: any,
}
/**
* AudioPlayerAction action component.
*
* @param sources
*
* * goal: a stream of `{src: string}` (as HTML audio
* [src](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/audio#attr-src))
* or a string (as a value of `src`).
* * AudioPlayer: `EventSource` for `ended` and `pause` events.
*
* @return sinks
*
* * state: a reducer stream.
* * status: a stream of action status.
* * result: a stream of action results.
* * AudioPlayer: a stream for `AudioPlayer` driver input.
*
*/
export function AudioPlayerAction(sources: Sources): Sinks {
const input$ = input(
sources.goal,
sources.cancel || xs.never(),
sources.AudioPlayer.events('ended'),
sources.AudioPlayer.events('pause'),
);
const reducer = transitionReducer(input$);;
const status$ = status(sources.state.stream);
const outputs = output(sources.state.stream);
return {
output: adapt(value$),
status: adapt(status$),
result: adapt(result$),
state: reducer,
status: status$,
...outputs
};
}

@@ -1,2 +0,2 @@

import {Stream} from 'xstream';
import xs from 'xstream';
import fromEvent from 'xstream/extra/fromEvent';

@@ -10,7 +10,7 @@ import {adapt} from '@cycle/run/lib/adapt';

* driver factory.
*
*
* @return {Driver} the HTML Audio Cycle.js driver function. It takes a
* stream of objects containing `[src](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/audio#attr-src).org/en-US/docs/Web/API/SpeechSynthesisUtterance#Properties)`
* fieldand returns a `EventSource`:
*
*
* * `EventSource.events(eventName)` returns a stream of `eventName`

@@ -33,3 +33,3 @@ * events from [`HTML Audio/Video Events`](https://www.w3schools.com/tags/ref_av_dom.asp).

return function audioPlayerDriver(sink$) {
sink$.addListener({
xs.fromObservable(sink$).addListener({
next: (args) => {

@@ -36,0 +36,0 @@ if (!args) {

import xs from 'xstream'
import {mockTimeSource} from '@cycle/time';
import {withState} from '@cycle/state';
import {

@@ -7,3 +8,3 @@ GoalID, GoalStatus, Status,

} from '@cycle-robot-drivers/action'
import {AudioPlayerAction} from '../src/AudioPlayerAction';
import {AudioPlayerAction as Action} from '../src/AudioPlayerAction';

@@ -46,5 +47,5 @@

}
const expectedValueStr$ = Time.diagram(`-x---|`);
const expectedStatusStr$ = Time.diagram(`-a-s-|`);
const expectedResultStr$ = Time.diagram(`---s-|`);
const expectedValueStr$ = Time.diagram(`-x`);
const expectedStatusStr$ = Time.diagram(`-a-s`);
const expectedResultStr$ = Time.diagram(`---s`);

@@ -58,3 +59,5 @@ // Create the action to test

});
const audioPlayerAction = AudioPlayerAction({
const sinks = withState((sources: any) => {
return Action(sources);
})({
goal: goal$,

@@ -78,5 +81,5 @@ AudioPlayer: {

// Run test
Time.assertEqual(audioPlayerAction.output, expectedValue$);
Time.assertEqual(audioPlayerAction.status, expectedStatus$);
Time.assertEqual(audioPlayerAction.result, expectedResult$);
Time.assertEqual(sinks.AudioPlayer, expectedValue$);
Time.assertEqual(sinks.status.drop(1), expectedStatus$);
Time.assertEqual(sinks.result, expectedResult$);

@@ -90,3 +93,4 @@ Time.run(done);

// Create test input streams with time
const goalNum$ = Time.diagram(`-0-1--|`);
const goalMark$ = Time.diagram(`-x----|`);
const cancel$ = Time.diagram(`---x--|`);
const events = {

@@ -96,5 +100,5 @@ ended: Time.diagram(`----x-|`),

}
const expectedValueNum$ = Time.diagram(`-0-1--|`);
const expectedStatusStr$ = Time.diagram(`-a--p-|`);
const expectedResultStr$ = Time.diagram(`----p-|`);
const expectedValueNum$ = Time.diagram(`-0-1`);
const expectedStatusStr$ = Time.diagram(`-a--p`);
const expectedResultStr$ = Time.diagram(`----p`);

@@ -104,8 +108,11 @@ // update strings to proper inputs

const goal_id = generateGoalID();
const goals = [{goal, goal_id}, null];
const goal$ = goalNum$.map(i => goals[i]);
// Create the action to test
const audioPlayerAction = AudioPlayerAction({
const goal$ = goalMark$.mapTo({
goal_id,
goal,
});
const sinks = withState((sources: any) => {
return Action(sources);
})({
goal: goal$,
cancel: cancel$.mapTo(null),
AudioPlayer: {

@@ -129,5 +136,5 @@ events: (eventName) => {

// Run test
Time.assertEqual(audioPlayerAction.output, expectedValue$);
Time.assertEqual(audioPlayerAction.status, expectedStatus$);
Time.assertEqual(audioPlayerAction.result, expectedResult$);
Time.assertEqual(sinks.AudioPlayer, expectedValue$);
Time.assertEqual(sinks.status.drop(1), expectedStatus$);
Time.assertEqual(sinks.result, expectedResult$);

@@ -141,3 +148,3 @@ Time.run(done);

// Create test input streams with time
const goalStr$ = Time.diagram(`-x-|`);
const cancel$ = Time.diagram(`-x-|`);
const events = {

@@ -147,10 +154,12 @@ ended: Time.diagram(`---|`),

}
const expectedValue$ = Time.diagram(`---|`);
const expectedStatus$ = Time.diagram(`---|`);
const expectedResult$ = Time.diagram(`---|`);
const expectedValue$ = Time.diagram(``);
const expectedStatus$ = Time.diagram(``);
const expectedResult$ = Time.diagram(``);
// Create the action to test
const goal$ = goalStr$.mapTo(null);
const audioPlayerAction = AudioPlayerAction({
goal: goal$,
const sinks = withState((sources: any) => {
return Action(sources);
})({
goal: xs.never(),
cancel: cancel$.mapTo(null),
AudioPlayer: {

@@ -164,5 +173,5 @@ events: (eventName) => {

// Run test
Time.assertEqual(audioPlayerAction.output, expectedValue$);
Time.assertEqual(audioPlayerAction.status, expectedStatus$);
Time.assertEqual(audioPlayerAction.result, expectedResult$);
Time.assertEqual(sinks.AudioPlayer, expectedValue$);
Time.assertEqual(sinks.status.drop(1), expectedStatus$);
Time.assertEqual(sinks.result, expectedResult$);

@@ -176,3 +185,4 @@ Time.run(done);

// Create test input streams with time
const goalNum$ = Time.diagram(`-0--1-|`);
const goalMark$ = Time.diagram(`-x----|`);
const cancel$ = Time.diagram(`----x-|`);
const events = {

@@ -182,5 +192,5 @@ ended: Time.diagram(`---x--|`),

}
const expectedValueNum$ = Time.diagram(`-0----|`);
const expectedStatusStr$ = Time.diagram(`-a-s--|`);
const expectedResultStr$ = Time.diagram(`---s--|`);
const expectedValueNum$ = Time.diagram(`-0`);
const expectedStatusStr$ = Time.diagram(`-a-s`);
const expectedResultStr$ = Time.diagram(`---s`);

@@ -190,6 +200,11 @@ // Create the action to test

const goal_id = generateGoalID();
const goals = [{goal, goal_id}, null];
const goal$ = goalNum$.map(i => goals[i]);
const audioPlayerAction = AudioPlayerAction({
const goal$ = goalMark$.mapTo({
goal_id,
goal,
});
const sinks = withState((sources: any) => {
return Action(sources);
})({
goal: goal$,
cancel: cancel$.mapTo(null),
AudioPlayer: {

@@ -213,5 +228,5 @@ events: (eventName) => {

// Run test
Time.assertEqual(audioPlayerAction.output, expectedValue$);
Time.assertEqual(audioPlayerAction.status, expectedStatus$);
Time.assertEqual(audioPlayerAction.result, expectedResult$);
Time.assertEqual(sinks.AudioPlayer, expectedValue$);
Time.assertEqual(sinks.status.drop(1), expectedStatus$);
Time.assertEqual(sinks.result, expectedResult$);

@@ -225,3 +240,4 @@ Time.run(done);

// Create test input streams with time
const goalNum$ = Time.diagram(`-0-1-1-|`);
const goalMark$ = Time.diagram(`-x-----|`);
const cancel$ = Time.diagram(`---x-x-|`);
const events = {

@@ -231,5 +247,5 @@ ended: Time.diagram(`----x--|`),

}
const expectedValueNum$ = Time.diagram(`-0-1---|`);
const expectedStatusStr$ = Time.diagram(`-a--p--|`);
const expectedResultStr$ = Time.diagram(`----p--|`);
const expectedValueNum$ = Time.diagram(`-0-1`);
const expectedStatusStr$ = Time.diagram(`-a--p`);
const expectedResultStr$ = Time.diagram(`----p`);

@@ -239,6 +255,11 @@ // Create the action to test

const goal_id = generateGoalID();
const goals = [{goal, goal_id}, null];
const goal$ = goalNum$.map(i => goals[i]);
const audioPlayerAction = AudioPlayerAction({
const goal$ = goalMark$.mapTo({
goal_id,
goal,
});
const sinks = withState((sources: any) => {
return Action(sources);
})({
goal: goal$,
cancel: cancel$.mapTo(null),
AudioPlayer: {

@@ -262,5 +283,5 @@ events: (eventName) => {

// Run test
Time.assertEqual(audioPlayerAction.output, expectedValue$);
Time.assertEqual(audioPlayerAction.status, expectedStatus$);
Time.assertEqual(audioPlayerAction.result, expectedResult$);
Time.assertEqual(sinks.AudioPlayer, expectedValue$);
Time.assertEqual(sinks.status.drop(1), expectedStatus$);
Time.assertEqual(sinks.result, expectedResult$);

@@ -274,3 +295,3 @@ Time.run(done);

// Create test input streams with time
const goalNum$ = Time.diagram(`-0--1----|`);
const goalMark$ = Time.diagram(`-0--1----|`);
const events = {

@@ -281,9 +302,9 @@ ended: Time.diagram(`-------x-|`),

const expecteds = [{
value: Time.diagram(`-0--x----|`),
status: Time.diagram(`-a---p---|`),
result: Time.diagram(`-----p---|`),
value: Time.diagram(`-0--x`),
status: Time.diagram(`-a---p`),
result: Time.diagram(`-----p`),
}, {
value: Time.diagram(`-----1---|`),
status: Time.diagram(`-----a-s-|`),
result: Time.diagram(`-------s-|`),
value: Time.diagram(`-----1`),
status: Time.diagram(`-----a-s`),
result: Time.diagram(`-------s`),
}];

@@ -294,7 +315,9 @@

const goals = [{src: 'dummy.org'}, {text: 'genius.ogg'}];
const goal$ = goalNum$.map(i => ({
const goal$ = goalMark$.map(i => ({
goal_id: goal_ids[i],
goal: goals[i],
}));
const audioPlayerAction = AudioPlayerAction({
const sinks = withState((sources: any) => {
return Action(sources);
})({
goal: goal$,

@@ -323,5 +346,5 @@ AudioPlayer: {

// Run test
Time.assertEqual(audioPlayerAction.output, expectedValue$);
Time.assertEqual(audioPlayerAction.status, expectedStatus$);
Time.assertEqual(audioPlayerAction.result, expectedResult$);
Time.assertEqual(sinks.AudioPlayer, expectedValue$);
Time.assertEqual(sinks.status.drop(1), expectedStatus$);
Time.assertEqual(sinks.result, expectedResult$);

@@ -328,0 +351,0 @@ Time.run(done);

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc