Como citado nos posts anteriores da série, ao ativar o AudioPlayer da Alexa, ela fornece alguns intents específicos para a obtenção do estado da execução. De modo geral, na skill da EximiaCo, utilizamos estes intents para duas tarefas principais: atualizar o estado de reprodução do episódio atual e gerenciar o playback contínuo de episódios.
import ask_sdk_core.utils as ask_utils from .player import Player from ask_sdk_core.dispatch_components import AbstractRequestHandler class PlaybackStartedHandler(AbstractRequestHandler): def can_handle(self, handler_input): return ask_utils.is_request_type("AudioPlayer.PlaybackStarted")(handler_input) def handle(self, handler_input): player = Player(handler_input) player.handle_playback_started() return handler_input.response_builder.response class PlaybackNearlyFinishedHandler(AbstractRequestHandler): def can_handle(self, handler_input): return ask_utils.is_request_type("AudioPlayer.PlaybackNearlyFinished")(handler_input) def handle(self, handler_input): player = Player(handler_input) player.handle_playback_nearly_finished() return handler_input.response_builder.response class PlaybackStoppedHandler(AbstractRequestHandler): def can_handle(self, handler_input): return ask_utils.is_request_type("AudioPlayer.PlaybackStopped")(handler_input) def handle(self, handler_input): player = Player(handler_input) player.handle_playback_stopped() return handler_input.response_builder.response class PlaybackFinishedHandler(AbstractRequestHandler): def can_handle(self, handler_input): return ask_utils.is_request_type("AudioPlayer.PlaybackFinished")(handler_input) def handle(self, handler_input): player = Player(handler_input) player.handle_playback_finished() return handler_input.response_builder.response
Com o intent AudioPlayer.PlaybackStarted
, armazenamos o episódio em execução atual, para que, posteriormente, ele possa ser recuperado durante as possíveis modificações no estado do playback.
def handle_playback_started(self): current_token = self.handler_input.request_envelope.request.token self.state.set_token(current_token) self.state.set_current_episode(current_token)
No intent AudioPlayer.PlaybackNearlyFinished
, a Alexa está informando que o episódio está perto do final, dando a possibilidade de definir o próximo episódio a ser executado. É importante reforçar a utilização do token ao enfileirar o episódio. Quando é iniciada a reprodução, é informado o token da execução atual e também o token esperado da execução anterior, para garantir a ordem da reprodução. Caso o token anterior informado não coincida com o existente no episódio anterior (ou o atual, caso não tenha finalizado a reprodução), a diretiva PlayDirective é ignorada.
def handle_playback_nearly_finished(self): current_episode = self.state.get_current_episode() if current_episode is None: return previous_episode = current_episode if not self.state.get_repeat(): previous_episode = self.episodes_provider.get_previous(current_episode) if previous_episode is None and self.state.get_loop(): previous_episode = self.episodes_provider.get_latest() if previous_episode is None: return self.handler_input.response_builder.add_directive( PlayDirective( play_behavior=PlayBehavior.ENQUEUE, audio_item=AudioItem( stream=Stream( token=previous_episode["pub"], url=previous_episode["address"], offset_in_milliseconds=0, expected_previous_token=current_episode["pub"]), metadata=None)) ).set_should_end_session(True)
Quando a execução do episódio é cancelada com um comando como “Pare”, ou “Cancelar”, é invocado o intent AudioPlayer.PlaybackStopped
. Neste intent, armazenamos o offset do episódio que está sendo reproduzido. Isto possibilita que a Alexa retome a reprodução do episódio quando for solicitado que ela continue a reprodução.
def handle_playback_stopped(self): millis = self.handler_input.request_envelope .request.offset_in_milliseconds self.state.set_offset(millis)
Ao finalizar o episódio, a Alexa invoca o intent AudioPlayer.PlaybackFinished
. Neste momento, apenas zeramos o offset do playback. Isso faz com que, ao iniciar um novo episódio, a Alexa comece a reprodução do início, e não do offset supostamente armazenado no estado da execução.
def handle_playback_finished(self): self.reset()
Nesta etapa, a skill está pronta. No próximo post da série, falaremos sobre o seu processo de publicação.
Para quem acompanha os drops da EximiaCo, ou para aqueles que irão acompanhar, a nossa skill está disponível no Marketplace da Alexa. Gostaríamos muito de conhecer a sua opinião.