Slides

Transcrição

Slides
Seu App na TV:
Desenvolvimento
para ChromeCast
Ivan de Aguirre
!
[email protected]
!
Twitter: IvAguirre
!
G+: plus.google.com/+IvanAguirreBr
Sender App:
Sender App:
Android
Sender App:
Android
iOS
Sender App:
Android
iOS
Chrome App
Sender App:
Android
iOS
Chrome App
Receiver App:
Sender App:
Android
iOS
Chrome App
Receiver App:
HTML 5
Sender App:
Android
iOS
Chrome App
Receiver App:
HTML 5
<video>
Sender App:
Android
iOS
Chrome App
Receiver App:
HTML 5
<video>
Registro
Sender App:
Android
iOS
Chrome App
Receiver App:
HTML 5
<video>
Registro
Application ID = URL
Workflow em detalhes
Workflow em detalhes
•
Descoberta do Chromecast.
Workflow em detalhes
•
Descoberta do Chromecast.
•
(Re)Conexão com o Chromecast: sessionID.
Workflow em detalhes
•
Descoberta do Chromecast.
•
(Re)Conexão com o Chromecast: sessionID.
•
Envio do Application ID ao Chromecast.
Workflow em detalhes
•
Descoberta do Chromecast.
•
(Re)Conexão com o Chromecast: sessionID.
•
Envio do Application ID ao Chromecast.
•
Chromecast acessa a URL do Application ID: Receiver App no ar!!
Workflow em detalhes
•
Descoberta do Chromecast.
•
(Re)Conexão com o Chromecast: sessionID.
•
Envio do Application ID ao Chromecast.
•
Chromecast acessa a URL do Application ID: Receiver App no ar!!
•
Sender envia a URL para o vídeo (media channel) e/ou…
Workflow em detalhes
•
Descoberta do Chromecast.
•
(Re)Conexão com o Chromecast: sessionID.
•
Envio do Application ID ao Chromecast.
•
Chromecast acessa a URL do Application ID: Receiver App no ar!!
•
Sender envia a URL para o vídeo (media channel) e/ou…
•
Envia texto (custom channel).
Workflow em detalhes
•
Descoberta do Chromecast.
•
(Re)Conexão com o Chromecast: sessionID.
•
Envio do Application ID ao Chromecast.
•
Chromecast acessa a URL do Application ID: Receiver App no ar!!
•
Sender envia a URL para o vídeo (media channel) e/ou…
•
Envia texto (custom channel).
•
Callbacks, callbacks, callbacks, callbacks…
Por dentro do Chromecast
Por dentro do Chromecast
•
Chrome Browser.
Por dentro do Chromecast
•
Chrome Browser.
•
HTML5, CSS 3, JavaScript.
Por dentro do Chromecast
•
Chrome Browser.
•
HTML5, CSS 3, JavaScript.
•
Limitações de memória e CPU.
Por dentro do Chromecast
•
Chrome Browser.
•
HTML5, CSS 3, JavaScript.
•
Limitações de memória e CPU.
•
Sem WebGL ou Chrome Extensions.
Por dentro do Chromecast
•
Chrome Browser.
•
HTML5, CSS 3, JavaScript.
•
Limitações de memória e CPU.
•
Sem WebGL ou Chrome Extensions.
•
Nada de Tabs, janelas, popups ou inputs.
Por dentro do Chromecast
•
Chrome Browser.
•
HTML5, CSS 3, JavaScript.
•
Limitações de memória e CPU.
•
Sem WebGL ou Chrome Extensions.
•
Nada de Tabs, janelas, popups ou inputs.
•
Suporte à WebAudio API.
Por dentro do Chromecast
•
Chrome Browser.
•
HTML5, CSS 3, JavaScript.
•
Limitações de memória e CPU.
•
Sem WebGL ou Chrome Extensions.
•
Nada de Tabs, janelas, popups ou inputs.
•
Suporte à WebAudio API.
•
Uma tag <video> ativa por vez.
developers.google.com/cast
!
developers.google.com/cast/
docs/ux_guidelines
!
developers.google.com/cast/
docs/design_checklist
Sender
com.android.support:appcompat-v7
!
com.android.support:mediarouter-v7
!
com.google.android.gms:play-services
Sender
GoogleApiClient.ConnectionCallbacks
GoogleApiClient.OnConnectionFailedListener
MediaRouter.Callback
Cast.Listener
ResultCallback<Cast.ApplicationConnectionResult>
RemoteMediaPlayer.OnStatusUpdatedListener
RemoteMediaPlayer.OnMetadataUpdatedListener
ResultCallback<RemoteMediaPlayer.MediaChannelResult>
Sender
GoogleApiClient.ConnectionCallbacks
GoogleApiClient.OnConnectionFailedListener
MediaRouter.Callback
Cast.Listener
ResultCallback<Cast.ApplicationConnectionResult>
RemoteMediaPlayer.OnStatusUpdatedListener
RemoteMediaPlayer.OnMetadataUpdatedListener
ResultCallback<RemoteMediaPlayer.MediaChannelResult>
Sender
github.com/googlecast/
CastCompanionLibrary-android
Sender + CastCompanionLibrary
public class MyApplication extends Application { private static VideoCastManager mCastMgr; public static VideoCastManager getVideoCastManager(Context ctx) { if (null == mCastMgr) { !
mCastMgr = VideoCastManager.initialize(ctx, "XYZ1234", null, /* activity com player */ null /* namespace */); mCastMgr.enableFeatures(… !
} mCastMgr.setContext(ctx); return mCastMgr; } }
Sender + CastCompanionLibrary
public class MainActivity extends ActionBarActivity { private VideoCastManager mVideoCastManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); BaseCastManager.checkGooglePlayServices(this); mVideoCastManager = MyApplication.getVideoCastManager( this); mVideoCastManager.reconnectSessionIfPossible(this, true, 5 /*sec*/); } }
Sender + CastCompanionLibrary
public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); !
getMenuInflater().inflate(R.menu.main, menu); !
mVideoCastManager.addMediaRouterButton(menu, R.id.media_route_menu_item); !
return true; }
Sender + CastCompanionLibrary
MediaMetadata mediaMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE); mediaMetadata.putString(MediaMetadata.KEY_TITLE, "Title: Chromecast na QCON RJ 2014"); mediaMetadata.putString(MediaMetadata.KEY_SUBTITLE, ""); mediaMetadata.putString(MediaMetadata.KEY_STUDIO, "Ivan de Aguirre Productions"); MediaInfo mediaInfo = new MediaInfo.Builder( "https://d2k4ls0ga9ks2.cloudfront.net/VID_20140727_225510282.mp4") .setContentType("video/mp4") .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED) .setMetadata(mediaMetadata) .build(); mVideoCastManager.startCastControllerActivity(this, mediaInfo, 0, true);
Receiver
Receiver
•
Default Receiver.
Receiver
•
Default Receiver.
•
Styled Receiver.
Receiver
•
Default Receiver.
•
Styled Receiver.
•
Custom Receiver.
Custom Receiver Mínimo
<html> <head> <title>Example minimum receiver</title> <script src="//www.gstatic.com/cast/sdk/libs/receiver/2.0.0/cast_receiver.js"></
script> </head> <body> <video id='media'/> <script> ... </script> </body> </html>
Custom Receiver Mínimo
<script> window.onload = function() { window.mediaElement=document.getElementById('media'); !
window.mediaManager = new cast.receiver.MediaManager( window.mediaElement); !
window.castReceiverManager = cast.receiver .CastReceiverManager.getInstance(); !
window.castReceiverManager.start(); } </script>
Exemplo 1
Exemplo 1
•
Custom Receiver para exibir propaganda e notificações no
telefone.
Exemplo 1
•
Custom Receiver para exibir propaganda e notificações no
telefone.
•
Envia URL do vídeo pelo Media Channel.
Exemplo 1
•
Custom Receiver para exibir propaganda e notificações no
telefone.
•
Envia URL do vídeo pelo Media Channel.
•
Envia texto pelo Custom Channel com as notificações.
Exemplo 1
•
Custom Receiver para exibir propaganda e notificações no
telefone.
•
Envia URL do vídeo pelo Media Channel.
•
Envia texto pelo Custom Channel com as notificações.
•
No Receiver exibe propagandas.
Exemplo 1 - Sender
public class MyApplication extends Application { private static VideoCastManager mCastMgr; public static VideoCastManager getVideoCastManager(Context ctx) { if (null == mCastMgr) { mCastMgr = VideoCastManager.initialize(ctx, "XYZ1234", "urn:x-­‐cast:org.gcastsamples.castnotifications"); // configurar opções... } !
mCastMgr.setContext(ctx); return mCastMgr; } }
Exemplo 1 - Sender
public class MyNotificationListenerService extends NotificationListenerService { @Override public void onNotificationPosted(StatusBarNotification statusBarNotification) { String msg = String.valueOf( statusBarNotification.getNotification().tickerText); !
try { !
MyApplication.getVideoCastManager(getApplicationContext()) .sendDataMessage(msg); !
} catch (TransientNetworkDisconnectionException e) { Log.e("NotificationListenerService", "Can't send message", e); } catch (NoConnectionException e) { Log.e("NotificationListenerService", "Can't send message", e); } } }
Exemplo 1 - Receiver
<div id="notification_banner" class="alert alert-­‐info" role="alert"> <h4>New Notification from your phone!!</h4> <p id="notification_text">Test!!!</p> </div> !
<div id="ad_banner" class="alert alert-­‐warning" role="alert"> <h4 id="ad_text">New Notification from your phone!!</h4> </div> !
<video id="media"/> Exemplo 1 - Receiver
window.mediaElement = document.getElementById('media'); window.mediaElement.addEventListener('playing', function(event) { advertising.start(); }); !
window.mediaManager = new cast.receiver.MediaManager(window.mediaElement); window.castReceiverManager = cast.receiver.CastReceiverManager.getInstance(); !
window.castReceiverManager.onSenderDisconnected = function(event) { if (window.castReceiverManager.getSenders().length == 0 && event.reason == cast.receiver.system.DisconnectReason.REQUESTED_BY_SENDER) { advertising.stop(); window.close(); } Exemplo 1 - Receiver
var nms = 'urn:x-­‐cast:org.gcastsamples.castnotifications'; var customMessageBus = window.castReceiverManager
.getCastMessageBus(nms); customMessageBus.onMessage = function(event) { showNotification(event.data);
} window.castReceiverManager.start();
Exemplo 2
Exemplo 2
•
Custom Receiver para exibir um gráfico.
Exemplo 2
•
Custom Receiver para exibir um gráfico.
•
www.flotcharts.org
Exemplo 2
•
Custom Receiver para exibir um gráfico.
•
www.flotcharts.org
•
A página do Custom Receiver quando acessada pelo Chromecast
é um Receiver.
Exemplo 2
•
Custom Receiver para exibir um gráfico.
•
www.flotcharts.org
•
A página do Custom Receiver quando acessada pelo Chromecast
é um Receiver.
•
A página do Custom Receiver quando acessada pelo Browser é
uma aplicação Web.
Exemplo 2
Exemplo 2 - Sender
public class MyApplication extends Application { !
private static DataCastManager mCastMgr; public static final String NAME_SPACE = "urn:x-­‐cast:org.gcastsamples.plotandcast"; public static DataCastManager getDataCastManager(Context ctx) { if (null == mCastMgr) { mCastMgr = DataCastManager.initialize(ctx,"XYZ123", NAME_SPACE); } !
mCastMgr.setContext(ctx); return mCastMgr; } }
Exemplo 2 - Sender
String json = getData(); !
mDataCastManager.sendDataMessage( json, MyApplication.NAME_SPACE);
Exemplo 2 - Receiver
<body>
<form id="plot_inputs"> … </form> <div id="content"> <div class="chart-­‐container"> <div id="placeholder"
class="chart-­‐placeholder"></div> </div> </body>
</div> Exemplo 2 - Receiver
if (navigator.userAgent.indexOf('CrKey') >= 0) { !
$('#plot_inputs').hide(); // form inputs $('.chart-­‐container').addClass('chart-­‐container-­‐for-­‐tv'); !
startChromeCastMode(); !
} else { !
startBrowserMode(); !
}
Exemplo 2 - Receiver
function startChromeCastMode() { window.onload = function() { window.castReceiverManager = cast.receiver.CastReceiverManager.getInstance(); var nms='urn:x-­‐cast:org.gcastsamples.plotandcast'; var customMessageBus = window.castReceiverManager.getCastMessageBus(nms); customMessageBus.onMessage = function(event) { var json = $.parseJSON(event.data);; plot(json); } window.castReceiverManager.start(); } }
Mirror e Presentation
Mirror e Presentation
•
Transmissão de Tela (Mirroring).
Mirror e Presentation
•
Transmissão de Tela (Mirroring).
•
Presentation API: API Level 17, Android 4.2+:
Mirror e Presentation
•
Transmissão de Tela (Mirroring).
•
Presentation API: API Level 17, Android 4.2+:
•
Em modo Mirror renderizar um Layout na TV (não há
receiver).
Mirror e Presentation
•
Transmissão de Tela (Mirroring).
•
Presentation API: API Level 17, Android 4.2+:
•
Em modo Mirror renderizar um Layout na TV (não há
receiver).
•
Wireless Display.
Mirror e Presentation
•
Transmissão de Tela (Mirroring).
•
Presentation API: API Level 17, Android 4.2+:
•
Em modo Mirror renderizar um Layout na TV (não há
receiver).
•
Wireless Display.
•
Suporta Miracast.
Mirror e Presentation
•
Transmissão de Tela (Mirroring).
•
Presentation API: API Level 17, Android 4.2+:
•
Em modo Mirror renderizar um Layout na TV (não há
receiver).
•
Wireless Display.
•
Suporta Miracast.
•
E Chromecast :)
Mirror e Presentation
•
Transmissão de Tela (Mirroring).
•
Presentation API: API Level 17, Android 4.2+:
•
•
Em modo Mirror renderizar um Layout na TV (não há
receiver).
•
Wireless Display.
•
Suporta Miracast.
•
E Chromecast :)
Plugin do Chromecast para Chrome: espelha aba e tela.
Mirror e Presentation
Mirror e Presentation
Exemplo 3 - Mirror e Presentation
Exemplo 3 - Mirror e Presentation
• Aplicação insere elementos em
uma lista.
Exemplo 3 - Mirror e Presentation
• Aplicação insere elementos em
uma lista.
• A lista é renderizada e
manipulada na TV.
Exemplo 3 - Mirror e Presentation
• Aplicação insere elementos em
uma lista.
• A lista é renderizada e
manipulada na TV.
• Não é casting!!
Exemplo 3 - Mirror e Presentation
public class ListPresentation extends Presentation { private RecyclerView mRecyclerView; private RecyclerView.LayoutManager mLayoutManager; private MyAdapter mAdapter; public ListPresentation(Context context, Display display) { super(context, display); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Context ctx = getContext(); Resources r = ctx.getResources(); setContentView(R.layout.presentation); mRecyclerView = (RecyclerView) findViewById(R.id.list); mLayoutManager = new LinearLayoutManager(ctx); mRecyclerView.setLayoutManager(mLayoutManager); mRecyclerView.setItemAnimator(new DefaultItemAnimator()); mAdapter = new MyAdapter(); mRecyclerView.setAdapter(mAdapter); } ...
Exemplo 3 - Mirror e Presentation
MediaRouter mMediaRouter = (MediaRouter)getSystemService(Context.MEDIA_ROUTER_SERVICE); MediaRouter.RouteInfo route = mMediaRouter.getSelectedRoute(MediaRouter.ROUTE_TYPE_LIVE_VIDEO); Display presentationDisplay = route != null ? route.getPresentationDisplay() : null; if (mPresentation != null && mPresentation.getDisplay() != presentationDisplay) { mPresentation.dismiss(); mPresentation = null; } if (mPresentation == null && presentationDisplay != null) { mPresentation = new ListPresentation(this, presentationDisplay); mPresentation.setOnDismissListener(mOnDismissListener); try { mPresentation.show(); } catch (WindowManager.InvalidDisplayException ex) { Log.w(TAG, "Display was removed in the meantime.", ex); mPresentation = null; } }
Exemplo 3 - Mirror e Presentation
MediaRouter mMediaRouter = (MediaRouter)getSystemService(Context.MEDIA_ROUTER_SERVICE); MediaRouter.RouteInfo route = mMediaRouter.getSelectedRoute(MediaRouter.ROUTE_TYPE_LIVE_VIDEO); Display presentationDisplay = route != null ? route.getPresentationDisplay() : null; if (mPresentation != null && mPresentation.getDisplay() != presentationDisplay) { mPresentation.dismiss(); android.media.MediaRouter
mPresentation = null; } não é app compact!!
if (mPresentation == null && presentationDisplay != null) { mPresentation = new ListPresentation(this, presentationDisplay); mPresentation.setOnDismissListener(mOnDismissListener); try { mPresentation.show(); } catch (WindowManager.InvalidDisplayException ex) { Log.w(TAG, "Display was removed in the meantime.", ex); mPresentation = null; } }
Exemplo 3 - Mirror e Presentation
ROUTE_TYPE_LIVE_AUDIO
MediaRouter mMediaRouter = (MediaRouter)getSystemService(Context.MEDIA_ROUTER_SERVICE); MediaRouter.RouteInfo route = mMediaRouter.getSelectedRoute(MediaRouter.ROUTE_TYPE_LIVE_VIDEO); Display presentationDisplay = route != null ? route.getPresentationDisplay() : null; if (mPresentation != null && mPresentation.getDisplay() != presentationDisplay) { mPresentation.dismiss(); android.media.MediaRouter
mPresentation = null; } não é app compact!!
if (mPresentation == null && presentationDisplay != null) { mPresentation = new ListPresentation(this, presentationDisplay); mPresentation.setOnDismissListener(mOnDismissListener); try { mPresentation.show(); } catch (WindowManager.InvalidDisplayException ex) { Log.w(TAG, "Display was removed in the meantime.", ex); mPresentation = null; } }
Chrome Sender
Chrome Sender
Chrome Sender
Developer Tools: <chromecast ip>:9222
Developer Tools: <chromecast ip>:9222
Developer Tools: <chromecast ip>:9222
•
window.location.reload(true);
Developer Tools: <chromecast ip>:9222
•
window.location.reload(true);
•
window.location.replace('http://myhost.com/receiver.html');
FAQ
FAQ
•
Sender/Receiver: HTTPS.
FAQ
•
Sender/Receiver: HTTPS.
•
URL do Receiver: HTTP em desenvolvimento, HTTPS em produção.
FAQ
•
Sender/Receiver: HTTPS.
•
URL do Receiver: HTTP em desenvolvimento, HTTPS em produção.
•
Múltiplas conexões ao receiver.
FAQ
•
Sender/Receiver: HTTPS.
•
URL do Receiver: HTTP em desenvolvimento, HTTPS em produção.
•
Múltiplas conexões ao receiver.
•
Segurança: é preciso implementar os mecanismos.
FAQ
•
Sender/Receiver: HTTPS.
•
URL do Receiver: HTTP em desenvolvimento, HTTPS em produção.
•
Múltiplas conexões ao receiver.
•
Segurança: é preciso implementar os mecanismos.
•
Media Player Library (Beta): Live Streaming, MPEG-DASH, Smooth
Streaming, DRM, etc..
FAQ
•
Sender/Receiver: HTTPS.
•
URL do Receiver: HTTP em desenvolvimento, HTTPS em produção.
•
Múltiplas conexões ao receiver.
•
Segurança: é preciso implementar os mecanismos.
•
Media Player Library (Beta): Live Streaming, MPEG-DASH, Smooth
Streaming, DRM, etc..
•
CORS.
FAQ
•
Sender/Receiver: HTTPS.
•
URL do Receiver: HTTP em desenvolvimento, HTTPS em produção.
•
Múltiplas conexões ao receiver.
•
Segurança: é preciso implementar os mecanismos.
•
Media Player Library (Beta): Live Streaming, MPEG-DASH, Smooth
Streaming, DRM, etc..
•
CORS.
•
Não esqueçam do iOS :)
Futuro
Futuro
•
Google TV?
Futuro
•
Google TV?
•
Chrome OS: integração no Google Drive na build
de desenvolvimento.
Futuro
•
Google TV?
•
Chrome OS: integração no Google Drive na build
de desenvolvimento.
•
Conexão fora da mesma rede Wifi.
Referências
developers.google.com/cast
cast.google.com/publish
github.com/googlecast
code.google.com/p/google-cast-sdk/issues/list
github.com/ivan-aguirre/chromecast_samples
ivan-aguirre.github.io/ccast-graph/receiver.html
ivan-aguirre.github.io/video-ccast-player/receiver.html
G+: Google Cast Developers
Seu App na TV: Desenvolvimento
para ChromeCast
Obrigado!!
Cast your questions :)
Ivan de Aguirre
!
[email protected]
!
Twitter: IvAguirre
!
G+: plus.google.com/+IvanAguirreBr

Documentos relacionados