1
votes

I am using the ask-sdk-core of the Alexa skill kit. I have the following LaunchRequestHandler and AudioIntentHandler. I face the issue that when I trigger the skill by just saying: "Alexa, speak to skillName" or "Alexa, start skillName" that somehow the request is sending AudioIntent and not LaunchRequest to the lambda function, thus, the audio stream starts playing. I was able to trigger both normal and the faulty behaviour via the developer console.

const LaunchRequestHandler = {
    canHandle(handlerInput) {
        return Alexa.getRequestType(handlerInput.requestEnvelope) === 'LaunchRequest';
    },
    handle(handlerInput) {
        const speakOutput = 'This message should be replied if the user launches the skill';
        return handlerInput.responseBuilder
            .speak(speakOutput)
            .reprompt(speakOutput)
            .addAudioPlayerStopDirective()
            .getResponse();
    }
};

And several other IntentHandlers. One of those IntentHandlers starts an audio stream.

const AudioIntentHandler = {
    canHandle(handlerInput) {
        return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
            && (Alexa.getIntentName(handlerInput.requestEnvelope) === 'AudioIntent'
            || Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.NextIntent'
            || Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.PreviousIntent');
    },
    handle(handlerInput) {
        // this code should only be triggered if an utterance of the intent has been said and 
        // not on launch
        const streamId = crypto.randomBytes(16).toString("hex");
        return handlerInput.responseBuilder
            .addAudioPlayerPlayDirective('REPLACE_ALL', mediaPath, streamId, 0, null, null)
            .withShouldEndSession(true)
            .getResponse();
    }
};

The audio intent handler is supported by a ResumeIntentHandler

const AudioResumeIntentHandler = {
    canHandle(handlerInput) {
        return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
            && Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.ResumeIntent';
    },
    handle(handlerInput) {
        // this code should only be triggered if an utterance of the intent has been said and 
        // not on launch
        const streamId = crypto.randomBytes(16).toString("hex");
        return handlerInput.responseBuilder
            .addAudioPlayerPlayDirective('REPLACE_ALL', mediaPath, streamId, 0, null, null)
            .withShouldEndSession(true)
            .getResponse();
    }
};

And the following AudioPlayer handler

const AudioRequestHandler = {
    canHandle(handlerInput) {
        return Alexa.getRequestType(handlerInput.requestEnvelope).includes('AudioPlayer.');
    },
    handle(handlerInput) {
        console.log(`AudioRequestHandler: ${handlerInput.requestEnvelope}`)
        
        if(Alexa.getRequestType(handlerInput.requestEnvelope) === 'AudioPlayer.PlaybackFailed') {
            console.log("Playback Failed : " + JSON.stringify(handlerInput.requestEnvelope.request.error, null, 2));
            return handlerInput.responseBuilder
                .speak('Something went wrong')
                .getResponse();
        } 
        return handlerInput.responseBuilder
            .getResponse();
    }
};

The skill acts as intended with one-shots e.g. Aelxa, ask skillName for help. I am able to reach all my non-audio intents. Also help intent, cancel, stop, etc work as intended. Why is the audio intent triggered on launch?

exports.handler = Alexa.SkillBuilders.custom()
.addRequestHandlers(
    LaunchRequestHandler,
    AudioRequestHandler,
    AudioPauseIntentHandler,
    AudioResumeIntentHandler,
    NormalReplyIntentHandler,
    AudioIntentHandler,
    HelpIntentHandler,
    CancelAndStopIntentHandler,
    FallbackIntentHandler,
    SessionEndedRequestHandler,
    IntentReflectorHandler)
.addErrorHandlers(
    ErrorHandler)
.lambda();

I added better logging. The faulty behaviour seems to happen after the second time the user starts the skill. First skill interaction works fine. After that, "start skillName" triggers "AudioIntentHandler". The request looks like follows:

type: IntentRequest
intent: {
  name: AudioIntent
  confirmationStatus: NONE
}

So it seems to me that my addRequestHandlers are not the issue here since its Alexa that sends the faulty intent. The AudioIntentHandler is triggered correctly based on the faulty request.

The faulty request includes AudioPlayer information. Probably from the last (first interaction) with the skill. I believe this could be the source of the bug?

AudioPlayer {
   offsetInMilliseconds: 3239,
   playerActivity: STOPPED,
}

Could it be that Alexa continues with the Audio Intent if the user starts the skill and Alexa detects that there exists a stopped Audio? Am I not clearing the audio player correctly on pause or stop?

const AudioPauseIntentHandler = {
    canHandle(handlerInput) {
        return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
            && Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.PauseIntent';
    },
    handle(handlerInput) {
        console.log('AudioPauseIntentHandler')
        const speakOutput = 'Audio stopped.';

        return handlerInput.responseBuilder
            .speak(speakOutput)
            .addAudioPlayerStopDirective()
            .addAudioPlayerClearQueueDirective('CLEAR_ALL')
            .getResponse();
    }
};
1
So in the developer console when you produced the faulty behavior is it the exact wording each time? Could you also provide the an excert from you index file where you .addRequestHandlers. The order here is sometimes an issue. Also have you tried adding !== 'LaunchRequest'? In the developer console what is your requestEnvelope when you have "failure".AhDev
I updated my question above. Could you please have a second look? I am highly appreciating your support!Andre
Glad the first suggestion helped. I have not done any development with Alexa using streams, however the general themes and usage throughout are pretty consistent. I have seen documentation that you can not send multiple audio directives in the same response. I have had similar issues with other directives. I will look to see if I can find more detail, but I would start there. This is a great topic and issue. Please make sure you respond here if you figure it out.AhDev

1 Answers

0
votes

I found the issue. As far as I know, it has nothing to do with my skill.json or lambda code. It's an Alexa thing and I was able to reproduce the same weird behaviour in other Alexa skills.

I am mainly testing in German. In English I usually starts skills using the following wake up words:

  • Alexa, talk to skillname
  • Alexa, start skillname

And that's the issue. In German, only "start" aka. "starte" works. "Talk to" aka. "spreche mit" seems to randomly trigger an intent within the skill instead of LaunchRequest.

I tested this with third-party skills and was able to reproduce the weird behaviour.

=> Fix: In German, start skill with "Alexa, starte skillname" instead of "Alexa, spreche mit skillname".