Chromecast na Qcon RJ

  • View
    424

  • Download
    1

  • Category

    Mobile

Preview:

Citation preview

Seu App na TV: Desenvolvimento para ChromeCast

Ivan de Aguirre !ivan.aguirre@gmail.com !Twitter: IvAguirre !G+: plus.google.com/+IvanAguirreBr

Sender App:

Sender App:Android

Sender App:Android

iOS

Sender App:Android

iOSChrome App

Sender App:Android

iOSChrome App

Receiver App:

Sender App:Android

iOSChrome App

Receiver App:HTML 5

Sender App:Android

iOSChrome App

Receiver App:HTML 5<video>

Sender App:Android

iOSChrome App

Receiver App:HTML 5<video>Registro

Sender App:Android

iOSChrome 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 - Senderpublic  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>  

    </div>  

</body>

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 Presentationpublic  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);  }  ...

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();          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

android.media.MediaRouter não é app compact!!

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

android.media.MediaRouter não é app compact!!

ROUTE_TYPE_LIVE_AUDIO

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 !

ivan.aguirre@gmail.com !

Twitter: IvAguirre !

G+: plus.google.com/+IvanAguirreBr

Recommended