Проблема со звуком Alexa-SDK

Я пытался создать навык alexa, который включает в себя звук. Я нашел отличное руководство здесь.

Вот их пример кода:

var stateByUser = {};
var podcastURL = "https://feeds.soundcloud.com/stream/309340878-user-652822799-episode-010-building-an-alexa-skill-with-flask-ask-with-john-wheeler.mp3";

// Entry-point for the Lambda
exports.handler = function(event, context) {
    var player = new SimplePlayer(event, context);
    player.handle();
};

// The SimplePlayer has helpful routines for interacting with Alexa, within minimal overhead
var SimplePlayer = function (event, context) {
    this.event = event;
    this.context = context;
};

// Handles an incoming Alexa request
SimplePlayer.prototype.handle = function () {
    var requestType = this.event.request.type;
    var userId = this.event.context ? this.event.context.System.user.userId : this.event.session.user.userId;
    var response = null;

    // On launch, we tell the user what they can do (Play audio :-))
    if (requestType === "LaunchRequest") {
        this.say("Welcome to the Simple Audio Player. Say Play to play some audio!", "You can say Play");

    // Handle Intents here - Play, Pause and Resume is all for now
    } else if (requestType === "IntentRequest") {
        var intent = this.event.request.intent;
        if (intent.name === "Play") {
            this.play(podcastURL, 0);

        } else if (intent.name === "AMAZON.PauseIntent") {
            // When we receive a Pause Intent, we need to issue a stop directive
            //  Otherwise, it will resume playing - essentially, we are confirming the user's action
            this.stop();

        } else if (intent.name === "AMAZON.ResumeIntent") {
            var lastPlayed = this.load(userId);
            var offsetInMilliseconds = 0;
            if (lastPlayed !== null) {
                offsetInMilliseconds = lastPlayed.request.offsetInMilliseconds;
            }

            this.play(podcastURL, offsetInMilliseconds);
        }
    } else if (requestType === "AudioPlayer.PlaybackStopped") {
        // We save off the PlaybackStopped Intent, so we know what was last playing
        this.save(userId, this.event);

    }
};

/**
 * Creates a proper Alexa response using Text-To-Speech
 * @param message
 * @param repromptMessage
 */
SimplePlayer.prototype.say = function (message, repromptMessage) {
    var response = {
        version: "1.0",
        response: {
            shouldEndSession: false,
            outputSpeech: {
                type: "SSML",
                ssml: "<speak> " + message + " </speak>"
            },
            reprompt: {
                outputSpeech: {
                    type: "SSML",
                    ssml: "<speak> " + message + " </speak>"
                }
            }
        }
    }
    this.context.succeed(response);
};

/**
 * Plays a particular track, from specific offset
 * @param audioURL The URL to play
 * @param offsetInMilliseconds The point from which to play - we set this to something other than zero when resuming
 */
SimplePlayer.prototype.play = function (audioURL, offsetInMilliseconds) {
    var response = {
        version: "1.0",
        response: {
            shouldEndSession: true,
            directives: [
                {
                    type: "AudioPlayer.Play",
                    playBehavior: "REPLACE_ALL", // Setting to REPLACE_ALL means that this track will start playing immediately
                    audioItem: {
                        stream: {
                            url: audioURL,
                            token: "0", // Unique token for the track - needed when queueing multiple tracks
                            expectedPreviousToken: null, // The expected previous token - when using queues, ensures safety
                            offsetInMilliseconds: offsetInMilliseconds
                        }
                    }
                }
            ]
        }
    }

    this.context.succeed(response);
};

// Stops the playback of Audio
SimplePlayer.prototype.stop = function () {
    var response = {
        version: "1.0",
        response: {
            shouldEndSession: true,
            directives: [
                {
                    type: "AudioPlayer.Stop"
                }
            ]
        }
    }

    this.context.succeed(response);
};

// Saves information into our super simple, not-production-grade cache
SimplePlayer.prototype.save = function (userId, state) {
    console.log("Save: " + userId);
    stateByUser[userId] = state;
};

// Load information from our super simple, not-production-grade cache
SimplePlayer.prototype.load = function (userId) {
    console.log("Load: " + userId);
    var state = null;
    if (userId in stateByUser) {
        state = stateByUser[userId];
        console.log("Loaded " + userId + " State: " + state);
    }
    return state;
};

Я пытаюсь реорганизовать этот код, чтобы он соответствовал формату, аналогичному формату викторины, пример, который предоставляет Amazon. Однако, когда я запускаю свой отредактированный код, я получаю сообщение об ошибке

TypeError: Cannot set property 'say' of undefined
at Object.<anonymous> (/Users/Rob/Desktop/super-simple-audio-player/index.js:47:28)

Вот моя попытка рефакторинга

"use strict";


var stateByUser = {};
var podcastURL = "https://p.scdn.co/mp3-preview/2385471a5d35709ad90e368dacabe4082af4541a?cid=null";
var Alexa = require("alexa-sdk");
// Entry-point for the Lambda
exports.handler = function(event, context) {
    var alexa = Alexa.handler(event, context);

    alexa.registerHandlers(SimplePlayer);

    alexa.execute();
};

// The SimplePlayer has helpful routines for interacting with Alexa, within minimal overhead
var SimplePlayer = {
  "LaunchRequest": function () {
        this.emit(":tell","Welcome to the Simple Audio Player. Say play to begin.");

    },
    "Play": function() {
        this.play(podcastURL, 0);
    },
    "AMAZON.PauseIntent": function() {
        this.stop();
    },
    "AMAZON.ResumeIntent": function () {
      var lastPlayed = this.load(userId);
      var offsetInMilliseconds = 0;
      if (lastPlayed !== null) {
          offsetInMilliseconds = lastPlayed.request.offsetInMilliseconds;
      }

      this.play(podcastURL, offsetInMilliseconds);
    },
    "AudioPlayer.PlaybackStopped": function () {
      this.save(userId, this.event);
    }
};

// Handles an incoming Alexa request


SimplePlayer.prototype.say = function (message, repromptMessage) {
    var response = {
        version: "1.0",
        response: {
            shouldEndSession: false,
            outputSpeech: {
                type: "SSML",
                ssml: "<speak> " + message + " </speak>"
            },
            reprompt: {
                outputSpeech: {
                    type: "SSML",
                    ssml: "<speak> " + message + " </speak>"
                }
            }
        }
    }
    this.context.succeed(response);
};

/**
 * Plays a particular track, from specific offset
 * @param audioURL The URL to play
 * @param offsetInMilliseconds The point from which to play - we set this to something other than zero when resuming
 */
SimplePlayer.prototype.play = function (audioURL, offsetInMilliseconds) {
    var response = {
        version: "1.0",
        response: {
            shouldEndSession: true,
            directives: [
                {
                    type: "AudioPlayer.Play",
                    playBehavior: "REPLACE_ALL", // Setting to REPLACE_ALL means that this track will start playing immediately
                    audioItem: {
                        stream: {
                            url: audioURL,
                            token: "0", // Unique token for the track - needed when queueing multiple tracks
                            expectedPreviousToken: null, // The expected previous token - when using queues, ensures safety
                            offsetInMilliseconds: offsetInMilliseconds
                        }
                    }
                }
            ]
        }
    }

    this.context.succeed(response);
};

// Stops the playback of Audio
SimplePlayer.prototype.stop = function () {
    var response = {
        version: "1.0",
        response: {
            shouldEndSession: true,
            directives: [
                {
                    type: "AudioPlayer.Stop"
                }
            ]
        }
    }

    this.context.succeed(response);
};

// Saves information into our super simple, not-production-grade cache
SimplePlayer.prototype.save = function (userId, state) {
    console.log("Save: " + userId);
    stateByUser[userId] = state;
};

// Load information from our super simple, not-production-grade cache
SimplePlayer.prototype.load = function (userId) {
    console.log("Load: " + userId);
    var state = null;
    if (userId in stateByUser) {
        state = stateByUser[userId];
        console.log("Loaded " + userId + " State: " + state);
    }
    return state;
};

Я добавил alexa-sdk и изменил export.handler и simplePlayer.prototype.handler (). Есть мысли, почему он не работает?

заранее спасибо


person robert    schedule 14.04.2017    source источник


Ответы (1)


Я действительно создал проект, на который вы ссылаетесь. Рад, что вы нашли это полезным.

При рефакторинге проекта вы изменили его с JS-объекта в стиле прототипа на объектный литерал. Оба подхода являются жизнеспособными, но литерал объекта становится проблемой при сохранении состояния для конкретного запроса (в частности, поля события и контекста).

Это также означает, что методы прототипа, определенные в проекте, недоступны из определения литерала объекта. Вам нужно создать экземпляр SimplePlayer (путем вызова new SimplePlayer(event, context)), прежде чем вы их получите.

Если вы хотите лучше понять компромисс между этими подходами, вы можете прочитать здесь:
Литерал объекта vs конструктор + прототип

Вот пример работы с Alexa SDK в соответствии с моим проектом. Он определяет функцию LaunchRequest как функцию-прототип, а не просто свойство:

SimplePlayer.prototype.LaunchRequest = function () {
    this.emit(":tell", "Welcome to the Simple Audio Player. Say play to begin.");
};

Вам также необходимо создать экземпляр SimplePlayer (а не просто ссылаться на него). При регистрации это должно выглядеть так:

alexa.registerHandlers(new SimplePlayer(event, context));

Надеюсь, что это имеет смысл, и удачи в этом! Сообщите мне, как это происходит (со мной всегда можно связаться по адресу https://gitter.im/bespoken/bst)

person John Kelvie    schedule 15.04.2017