[Course] Project 3: Build a Podcast Player


#23

OK, tried it on the physical hardware.

  • The Jovo debugger plays the first MP3 and doesn’t handle the next-episode logic.
  • The Alexa developer console says “Enjoy”,complains that AudioPlayer isn’t supported, and stops.
  • The Echo Dot says “Enjoy”, pauses an annoyingly long time (perhaps because I told it to start at minute 38 for debugging and it’s being slow about downloading and discarding the earlier data?), then is either pausing again or failing to handle the next-episode logic. I’m betting the latter, since for episode 55 I did leave it starting at offset 0.
  • To check the initial pause, I put the offset back to 0, deployed, and launched it again on the Echo Dot. This time it said “Enjoy” and immediately started playing the podcast. So it looks like my guess is correct, and we just aren’t handling offset very efficiently. That’s tolerable in beta code, but I hope it’s going to be fixed. In the meantime, I can try to kluge around it by using a different audio file for the first “episode” in this testcase… However, I did let it run, and when it got to the end of the file it still did not advance.

Should there be some indication in the console that PlaybackNearlyFinished has enqueued the next episode?

Another question, while I’m here: The deploy/run setup apparently runs the app’s logic on my own machine’s instance of Jovo, with your server acting as a proxy to avoid my needing to be findable via DNS. That’s fine for testing, but eventually I’m going to want the back-end running as an elastic/scalable service. Does the Jovo CLI have an easy way to publish the app as a Lambda or Web Function or similar, or would we have to set that up ourselves? (If the answer is that this is only available if we buy a subscription, that’s not wholly unreasonable… but it makes Jovo much less useful for those of us who are writing code to donate to our favorite public radio show or otherwise are trying to keep it cheap.)


#24

I should note that the checked-in podcast player code handles the AlexaSkill.Playback... events differently, by having a separate alexa\handler.js file rather than embedding it in the app.js handler. This makes me suspect that the sample code in the tutorial is actually incorrect.

As a sanity check on that:

  • Has anyone been able to take the jovo-sample-podcast-player, comment out its standard handler, plug in the handler from Step 2 of this project, and get the expected continue-to-next-episode behavior?
  • Or is the code in the document sufficiently outdated that this experiment simply doesn’t work?
  • Or is it definitely something about my copy or my environment?

(I’d prefer to work my way through the tutorial to make sure I understand what this app is doing, and how, before I start modifying it for the archives I’m interested in… but if the tutorial is wrong, I can try diving in at the deep end instead.)

============================================

Experimenting with the unaltered podcast player, as checked into git, running in the debugger as Amazon:

Previous doesn’t work if you’re playing the last episode (56); we get silence. If we hit Previous again, we do get episode 54. Hitting Next from there we get silence; a second Next gets us back to 56. This misbehavior might be related to why my Step 2 experimental auto-previous transition is failing. We can test that by using a handler which skips to 54 rather than 55…

ListIntent displays on the debugger console, but even though I’m running as an Echo Without Screen the debugger does not interrupt playback to speak the list. Ditto HelpIntent, and previous/next when at the end of the list. Is this an artifact of the debugger not having a speech synth library available? (I see that the “advanced” mode displays these responses in the Conversation, which makes some sense to me… except that I would expect these to imply a pause to give the user a chance to pick something else before resuming.)

StopIntent/PauseIntent don’t seem to be implemented. Ditto ChooseFromListIntent.

FirstEpisodeIntent may be misnamed; it’s really First Available / Earliest Available / First In List. Which wouldn’t be a problem except that saying “play episode one” and getting episode 52 will confuse users. I think the dialog could be improved here.


#25

There’s a lot to digest here. A couple of notes on some of the points you’ve mentioned.

Unaltered podcast-player (https://github.com/jovotech/jovo-sample-podcast-player):

  • I can’t reproduce the issue of having to trigger an intent, e.g. PreviousIntent, twice to make it work
  • the debugger’s audio player support isn’t the greatest. You might run into a couple of issues here and there. One of them is the PauseIntent not actually pausing the audio playback.
  • replacing the handler with the one from step 2 worked for me. Just a couple of things: did you delete the two platform-specific handlers ( app.setAlexaHandler(AlexaHandler); app.setGoogleAssistantHandler(GoogleHandler);)? Also, the audio player intents in the AUDIOPLAYER state are outdated. Instead of being named AudioPlayer.PlaybackStarted they should be AlexaSkill.PlaybackStarted

General:

  • the Alexa simulator doesn’t support the audio player, never did, and probably never will.
  • yes, Jovo supports deployment to other services. Check out https://www.jovo.tech/docs/hosting

#27

Sanity check: You said

I would have hoped that we’d be removing dependencies upon Alexa-specific values, and writing platform-independent code, wherever possible… Is there a plan to improve this, eg by providing “boilerplate” platform event handlers which forward the events to a shared generic solution?

===================================

Another “this probably exists but I didn’t see it” item: Is there an easier way to get the code from git set up to be runnable than using jovo new to create a separate directory and then copying the checked-out files into it? (In other words, to just run the portion of the new process which creates the stuff .gitignore says not to check in)?

=======================================

Sigh. Another point of confusion: When I try the Google- enabled version of Step 2 as shown in the course, using the debugger in Google Speaker mode, it gets to the end of Episode 56… and then plays 56 again rather than going to 55. This again seems to be related to @curiousdustin’s note at the very top of this thread, back in May of last year. But that Issue is marked Closed. Should I try to get it reopened or start an “It’s happening again” issue? (Note that this is with the Step 2 version of app.js, not the checked-in version, so it may just be that something didn’t get included in the stripped-down google handler in this chapter.)


#28

Step 4, adding Alexa pause: It looks like the debugger doesn’t support that. It might be good to explicitly say so, and tell folks to test on the real hardware.

At some time I may need to take a look at the debugger source and see whether some of these features can be added…

Step 4, continued: After pasting in the app.js changes from the document, “Alexa, open my podcast player” replies "There was a problem with the requested skill's response." Console shows "Validation exception in class: Stream field cannot be null at field url". Best initial guess I’ve got is that the this.$user.isNew() test is failing because I’ve used previous versions of the Alexa app, and that I’d need to completely delete and recreate that to make this work.

Simpler solution might be to reorganize the test to explicitly check for the null:

        episode = this.$user.$data.currentEpisode;
        if (episode==null || !episode.startsWith("https:")) {
            episode = 'https://traffic.libsyn.com/voicebot/Jan_Konig_on_the_Jovo_Open_Source_Framework_for_Voice_App_Development_-_Voicebot_Podcast_Ep_56.mp3';

            this.$user.$data.currentEpisode = episode;
        }

Note that I also changed the URI from http: as shown in the document to https:, since the Amazon APIs require that. That required adding a sanity-check test since a previous run had stored the “http:” URI; I could have manually reset that but this seemed a more robust fix.)

That’s bringing the system up OK. But testing on my Echo, if I try to either pause or stop and then resume or play, it is complaining "SpeechletResponse was null", and if I just re-Open the Alexa app it’s starting from offset zero again. So something about the offset store and recover in the document’s version of the code still isn’t right.

Trying to decide whether it’s worth my chasing down the error, or if I should just move on to the next section of the course.

One of the challenges of writing tutorials is always keeping them synchronized with working code as the latter continues to evolve…

=======================================================

Testing resume with the “production” (checked in) code, I’m still finding that the resume operation (play with offset) takes a surprisingly long time to get back to the offset point and start producing audio again. If I pause at offset 1104351 (1104 seconds, 18.4 minutes), then after saying “resume” and hearing the Echo acknowledge the request I get no audio for about 112 seconds (1.8 minutes). Admittedly that’s 10 times faster than listening through what I’ve already heard… but it’s MUCH slower than most other Alexa audio players. This strongly suggests that we’re failing to take advantage of APIs/caches/something which would allow better responsiveness. I haven’t worked directly with the Alexa yet (I was hoping Jovo would be a shortcut into that), so I don’t have any insights yet into exactly which of those is our mistake… but clearly we’re missing a bet. “If it happens, it must be possible.”

Another glitch: Having resumed, When I got to the end of an episode and it auto-advanced to the next, the checked in code started that at offset 1116811, and did so without a delay.

Yet when I paused and resumed, we hit the delay again.

So in addition to our apparently not clearing the offset when we change episodes, there seems to be some bit of state being stored somewhere that our resume didn’t handle but that advancing to the next episode did.

Very strange. And again: If it happens, it must be possible, and we’re doing something wrong in the example.

(A product tester walks into a bar and orders a beer. Orders one beer. Orders zero beers. Orders -1 beers. Orders an ostrich. Orders ostrich beer. Orders beer ostrich. Orders beer one. Orders a refill on the beer. Orders a refill on the ostrich. Orders a beer for the ostrich. Orders a beer for tomorrow. Orders a beer for yesterday. Orders low-cal beer. Orders low-cal whiskey. Orders beer, no, whiskey. Orders beer, no whiskey. Orders a boar, a bear, a bar, a bier, a peer, a peel, and a whisk broom. …)

========================================================

Sorry about the edits, but this system doesn’t permit more than three posts from one person in a row, no matter how far apart they are in time…

For what it’s worth: I’ve been making progress adapting this player to my needs:

All my episodes are datestamped. So for prototyping, rather than use an episodes.json file, I instead use earliest-episode’s date and current date, and navigate between episodes with some date math. A “does this URL actually exist” probe is called in a loop incrementing or decrementing the date (as appropriate) to skip missing episodes. I’ll be modifying the spoken dialog to select by date rather than select by episode number. Note that this approach avoids needing to update the episode list every time a new edition is released.

Eventually I will want selection by episode numbers or content too, and since those aren’t in synch with dates I’ll need to recreate a lookup table. But that’s being deferred to the second pass; right now I just want something that lets me navigate through history of the radio show this is supporting.


#29

Just an update: I’m on version 0.2 of my skill now, having gone back and done some redesign so it updates its data structures from the same database that drives the program’s website. I have a long Todo list, but the things I most need to deal with right now are adding a by-broadcast-date index (to handle rebroadcasts and broadcasts in other than production order) and starting to bring up the other platforms (hopefully most of my changes are at the app logic level and won’t break the sample’s cross-platform capability).

One Alexa annoyance discovered which is probably going to be a pain to work around: If you pause and then resume while the audio is still in Alexa’s cache, it can just resume deciding and playing. If you ask the player to resume after using another audio app, so that cache was flushed, Alexa has to decompress the MP3 from the start to get back to the time-based offset with the right compression setup… and if your MP3 is a single hour-long episode, that “pre-roll” can take a significantly long time, longer that the user will really be comfortable with. And I’m not sure whether or how the skill can detect whether or not the pre-roll delay will occur, so I can’t issue an appropriate “this will take a minute, please stand by” message only when this delay will occur. I wouldn’t be shocked if Amazon’s advice was just “don’t have long compressed audio files, then, or don’t try to restart at a saved offset in them”, but I don’t have any control over how the audio is stored and I would like to resume when we can do so reasonably.

Best thought I have right now is to not suggest resuming right after starting the app – in that case, force restarting the episode from the beginning. Not really user friendly, but maybe more so than leaving them hanging for a long, unspecified time, or warning them and then not having a delay.

If anyone has already fought with this and found a better way to run that interaction, I’m eager for suggestions!