import { Alexa } from "./alexa" ; import { ServiceRequest , RequestType , SessionEndedReason } from "./service-request" ; import { EventEmitter } from "events" ; import { AudioItem } from "./audio-item" ; export enum AudioPlayerActivity { BUFFER_UNDERRUN , FINISHED , IDLE , PLAYING , PAUSED , STOPPED } /**
 * Emulates the behavior of the audio player
 */ export class AudioPlayer { public static DirectivePlay = "AudioPlayer.Play" ; public static DirectiveStop = "AudioPlayer.Stop" ; public static DirectiveClearQueue = "AudioPlayer.ClearQueue" ; public static PlayBehaviorReplaceAll = "REPLACE_ALL" ; public static PlayBehaviorEnqueue = "ENQUEUE" ; public static PlayBehaviorReplaceEnqueued = "REPLACE_ENQUEUED" ; private _emitter : EventEmitter = null ; private _playing : AudioItem = null ; private _queue : Array < AudioItem > = [ ] ; private _activity : AudioPlayerActivity = null ; private _suspended : boolean = false ; public constructor ( public alexa ) { this . _activity = AudioPlayerActivity . IDLE ; this . _emitter = new EventEmitter ( ) ; } public enqueue ( audioItem , playBehavior ) { if ( playBehavior === AudioPlayer . PlayBehaviorEnqueue ) { this . _queue . push ( audioItem ) ; } else if ( playBehavior === AudioPlayer . PlayBehaviorReplaceAll ) { if ( this . isPlaying ( ) ) { this . playbackStopped ( ) ; } this . _queue = [ ] ; this . _queue . push ( audioItem ) ; } else if ( playBehavior === AudioPlayer . PlayBehaviorReplaceEnqueued ) { this . _queue = [ ] ; this . _queue . push ( audioItem ) ; } if ( ! this . isPlaying ( ) ) { this . playNext ( ) ; } } public activity ( ) { return this . _activity ; } public playNext ( ) { if ( this . _queue . length === 0 ) { return ; } this . _playing = this . dequeue ( ) ; if ( this . _playing . stream . url . startsWith ( "http:" ) ) { this . alexa . sessionEnded ( SessionEndedReason . ERROR , { type : "INVALID_RESPONSE" , message : "The URL specified in the Play directive must be HTTPS" } ) ; } else { this . playbackStarted ( ) ; } } public suspend ( ) { this . _suspended = true ; this . playbackStopped ( ) ; } public suspended ( ) { return this . _suspended ; } param offset public playbackOffset ( offset ) { if ( this . isPlaying ( ) ) { this . playing ( ) . stream . offsetInMilliseconds = offset ; } } public on ( audioPlayerRequest , listener ) { this . _emitter . on ( audioPlayerRequest , listener ) ; } public once ( audioPlayerRequest , listener ) { this . _emitter . once ( audioPlayerRequest , listener ) ; } public resume ( ) { this . _suspended = false ; this . playbackStarted ( ) ; } public playbackNearlyFinished ( callback ? ) { this . audioPlayerRequest ( RequestType . AudioPlayerPlaybackNearlyFinished , callback ) ; } public playbackFinished ( callback ? ) { this . _activity = AudioPlayerActivity . FINISHED ; this . audioPlayerRequest ( RequestType . AudioPlayerPlaybackFinished , callback ) ; this . playNext ( ) ; } public playbackStarted ( callback ? ) { this . _activity = AudioPlayerActivity . PLAYING ; this . audioPlayerRequest ( RequestType . AudioPlayerPlaybackStarted , callback ) ; } public playbackStopped ( callback ? ) { this . _activity = AudioPlayerActivity . STOPPED ; this . audioPlayerRequest ( RequestType . AudioPlayerPlaybackStopped , callback ) ; } private audioPlayerRequest ( requestType , callback ? ) { const self = this ; const nowPlaying = this . playing ( ) ; const serviceRequest = new ServiceRequest ( this . alexa . context ( ) ) ; serviceRequest . audioPlayerRequest ( requestType , nowPlaying . stream . token , nowPlaying . stream . offsetInMilliseconds ) ; this . alexa . callSkill ( serviceRequest , function ( error , response , request ) { if ( callback !== undefined && callback !== null ) { callback ( error , response , request ) ; } self . _emitter . emit ( requestType , nowPlaying . clone ( ) ) ; } ) ; } public directivesReceived ( directives ) { for ( let directive of directives ) { this . handleDirective ( directive ) ; } } private handleDirective ( directive ) { if ( directive . type === AudioPlayer . DirectivePlay ) { let audioItem = new AudioItem ( directive . audioItem ) ; let playBehavior = directive . playBehavior ; this . enqueue ( audioItem , playBehavior ) ; } else if ( directive . type === AudioPlayer . DirectiveStop ) { if ( this . suspended ( ) ) { this . _suspended = false ; } else if ( this . playing ( ) ) { this . playbackStopped ( ) ; } } } public isPlaying ( ) { return ( this . _activity === AudioPlayerActivity . PLAYING ) ; } private dequeue ( ) { const audioItem = this . _queue [ 0 ] ; this . _queue = this . _queue . slice ( 1 ) ; return audioItem ; } public playing ( ) { return this . _playing ; } }