Blog

  • Android Sender App Receiver App

    A sender application or Google Cast application refers to an app running on a mobile device (the sender device).

     

    Setup

    • Download the latest version of the Android SDK using the Android SDK Manager.

    • Install the Android Support Libraries through the Android SDK Manager. The support libraries need to be revision 19.0.1 or later.

    • Install the Google Play services SDK through the Android SDK Manager. The Google Play services SDK needs to be revision 4.2 or later.

     

    Add Libraries

    The following libraries are required :

    • android-support-v7-appcompat : path to this library is <SDK install location>/extras/android/support/v7/appcompat

    • android-support-v7-mediarouter : path to this library is <SDK install location>/extras/android/support/v7/mediarouter

    • google-play-services_lib : path to this library is <SDK install location>/extras/google/google_play_services/libproject/google-play-services_lib

     

    Note

    • Import these libraries as library projects for your IDE instead of including their JAR files
    • Android-support-v7-mediarouter has a dependency on android-support-v7-appcompat, so add it by selecting the android-support-v7-mediarouter project Properties, then select Android, and in the Libraries list, add android-support-v7-appcompat.
    • Ensure the build target for each of the imported libraries is same : select the library project Properties and then select Android. Select a different Project Build Target, select "Apply", then re-select the desired target (> API 17) and hit "Apply" again.

     

    Development

    Android manifest

    Add following configuration in AndroidManifest.xml file to use the Cast SDK:

     

    Internet permission

    
     

     

    uses-sdk

    The minimum Android SDK version that the Cast SDK supports is 9 (GingerBread).

     
     

     

    meta-data

    
     

     

    android:theme

    The applicationís theme needs to be correctly set based on the minimum Android SDK version.

    
           ...
        
     

     

    Adding the Cast Button

    The MediaRouter framework provides a Cast button and a list selection dialog for selecting a route. There are three ways to support a Cast button:

    • Using the MediaRouter ActionBar provider: android.support.v7.app.MediaRouteActionProvider

    • Using the MediaRouter Cast button: android.support.v7.app.MediaRouteButton

    • Developing a custom UI with the MediaRouter APIís and MediaRouter.Callback

    This blog describes the use of the MediaRouteActionProvider to add the Cast button to the ActionBar.This action bar button handles all of the state logic needed for hiding or displaying the casting button, as well as coloring it when the app has connected to a casting device.Add the media routing button to our menu.xml as follows :

     

      
    

     

    Add some values to strings.xml, such as the video URL, receiver application ID and general UI strings.You'll need to replace app_id

    with your application ID, and video_url with a video that you would want to play.

     

    Chromecast App
    xxxxx
    xxxxx
    Play Video
    Pause Video
    Resume Video
    Your Video Title Here
    video/mp4
     

     

    The UI for this activity consists of a single button that will start a video if the app is connected to a casting device, or can pause/resume a video once it has been started, and the media router button in the action bar.The action bar button will display only if you are connected with chromecast device on the same wifi network.

     

    Add following code to your casting activity i.e, MainActivity.java

     

    package com.example.chromecastapp;
    
    import android.os.Bundle;
    import android.support.v4.view.MenuItemCompat;
    
    import android.support.v7.app.ActionBarActivity;
    import android.support.v7.app.MediaRouteActionProvider;
    import android.support.v7.media.MediaRouteSelector;
    import android.support.v7.media.MediaRouter;
    import android.support.v7.media.MediaRouter.RouteInfo;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    
    import com.google.android.gms.cast.ApplicationMetadata;
    import com.google.android.gms.cast.Cast;
    import com.google.android.gms.cast.CastDevice;
    import com.google.android.gms.cast.CastMediaControlIntent;
    import com.google.android.gms.cast.MediaInfo;
    import com.google.android.gms.cast.MediaMetadata;
    import com.google.android.gms.cast.MediaStatus;
    import com.google.android.gms.cast.RemoteMediaPlayer;
    import com.google.android.gms.common.ConnectionResult;
    import com.google.android.gms.common.api.GoogleApiClient;
    import com.google.android.gms.common.api.ResultCallback;
    import com.google.android.gms.common.api.Status;
    
    import java.io.IOException;
    
    public class MainActivity extends ActionBarActivity {
    
        private Button mButton;
    
        private MediaRouter mMediaRouter;
        private MediaRouteSelector mMediaRouteSelector;
        private MediaRouter.Callback mMediaRouterCallback;
        private CastDevice mSelectedDevice;
        private GoogleApiClient mApiClient;
        private RemoteMediaPlayer mRemoteMediaPlayer;
        private Cast.Listener mCastClientListener;
        private boolean mWaitingForReconnect = false;
        private boolean mApplicationStarted = false;
        private boolean mVideoIsLoaded;
        private boolean mIsPlaying;
    
        @Override
        protected void onCreate( Bundle savedInstanceState ) {
            super.onCreate( savedInstanceState );
            setContentView( R.layout.activity_main );
    
            mButton = (Button) findViewById( R.id.button );
            mButton.setOnClickListener( new OnClickListener() {
                @Override
                public void onClick( View v ) {
                   if( !mVideoIsLoaded )
                       startVideo();
                   else
                       controlVideo();
                }
            });
    
            initMediaRouter();
        }
    
        private void initMediaRouter() {
            // Configure Cast device discovery
            mMediaRouter = MediaRouter.getInstance( getApplicationContext() );
            mMediaRouteSelector = new MediaRouteSelector.Builder()
                    .addControlCategory( CastMediaControlIntent.categoryForCast( getString( R.string.app_id ) ) )
                    .build();
            mMediaRouterCallback = new MediaRouterCallback();
        }
    
        private void initCastClientListener() {
            mCastClientListener = new Cast.Listener() {
                @Override
                public void onApplicationStatusChanged() {
                }
    
                @Override
                public void onVolumeChanged() {
                }
    
                @Override
                public void onApplicationDisconnected( int statusCode ) {
                    teardown();
                }
            };
        }
    
        private void initRemoteMediaPlayer() {
            mRemoteMediaPlayer = new RemoteMediaPlayer();
            mRemoteMediaPlayer.setOnStatusUpdatedListener( new RemoteMediaPlayer.OnStatusUpdatedListener() {
                @Override
                public void onStatusUpdated() {
                    MediaStatus mediaStatus = mRemoteMediaPlayer.getMediaStatus();
                    mIsPlaying = mediaStatus.getPlayerState() == MediaStatus.PLAYER_STATE_PLAYING;
                }
            });
    
            mRemoteMediaPlayer.setOnMetadataUpdatedListener( new RemoteMediaPlayer.OnMetadataUpdatedListener() {
                @Override
                public void onMetadataUpdated() {
                }
            });
        }
    
        private void controlVideo() {
            if( mRemoteMediaPlayer == null || !mVideoIsLoaded )
                return;
    
            if( mIsPlaying ) {
                mRemoteMediaPlayer.pause( mApiClient );
                mButton.setText( getString( R.string.resume_video ) );
            } else {
                mRemoteMediaPlayer.play( mApiClient );
                mButton.setText( getString( R.string.pause_video ) );
            }
        }
    
        private void startVideo() {
            MediaMetadata mediaMetadata = new MediaMetadata( MediaMetadata.MEDIA_TYPE_MOVIE );
            mediaMetadata.putString( MediaMetadata.KEY_TITLE, getString( R.string.video_title ) );
    
            MediaInfo mediaInfo = new MediaInfo.Builder( getString( R.string.video_url ) )
                    .setContentType( getString( R.string.content_type_mp4 ) )
                    .setStreamType( MediaInfo.STREAM_TYPE_BUFFERED )
                    .setMetadata( mediaMetadata )
                    .build();
            try {
                mRemoteMediaPlayer.load( mApiClient, mediaInfo, true )
                        .setResultCallback( new ResultCallback() {
                            @Override
                            public void onResult( RemoteMediaPlayer.MediaChannelResult mediaChannelResult ) {
                                if( mediaChannelResult.getStatus().isSuccess() ) {
                                    mVideoIsLoaded = true;
                                    mButton.setText( getString( R.string.pause_video ) );
                                }
                            }
                        } );
            } catch( Exception e ) {
            }
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            // Start media router discovery
            mMediaRouter.addCallback( mMediaRouteSelector, mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN );
        }
    
        @Override
        protected void onPause() {
            if ( isFinishing() ) {
                // End media router discovery
                mMediaRouter.removeCallback( mMediaRouterCallback );
            }
            super.onPause();
        }
    
        private class MediaRouterCallback extends MediaRouter.Callback {
    
            @Override
            public void onRouteSelected(MediaRouter router, RouteInfo info) {
                initCastClientListener();
                initRemoteMediaPlayer();
    
                mSelectedDevice = CastDevice.getFromBundle( info.getExtras() );
    
                launchReceiver();
            }
    
            @Override
            public void onRouteUnselected( MediaRouter router, RouteInfo info ) {
                teardown();
                mSelectedDevice = null;
                mButton.setText( getString( R.string.play_video ) );
                mVideoIsLoaded = false;
            }
        }
    
        private void launchReceiver() {
            Cast.CastOptions.Builder apiOptionsBuilder = Cast.CastOptions
                    .builder( mSelectedDevice, mCastClientListener );
    
            ConnectionCallbacks mConnectionCallbacks = new ConnectionCallbacks();
            ConnectionFailedListener mConnectionFailedListener = new ConnectionFailedListener();
            mApiClient = new GoogleApiClient.Builder( this )
                    .addApi( Cast.API, apiOptionsBuilder.build() )
                    .addConnectionCallbacks( mConnectionCallbacks )
                    .addOnConnectionFailedListener( mConnectionFailedListener )
                    .build();
    
            mApiClient.connect();
        }
    
        private class ConnectionCallbacks implements GoogleApiClient.ConnectionCallbacks {
    
            @Override
            public void onConnected( Bundle hint ) {
                if( mWaitingForReconnect ) {
                    mWaitingForReconnect = false;
                    reconnectChannels( hint );
                } else {
                    try {
                        Cast.CastApi.launchApplication( mApiClient, getString( R.string.app_id ), false )
                                .setResultCallback( new ResultCallback() {
                                    @Override
                                    public void onResult(Cast.ApplicationConnectionResult applicationConnectionResult) {
                                        Status status = applicationConnectionResult.getStatus();
                                        if( status.isSuccess() ) {
                                            //Values that can be useful for storing/logic
                                            ApplicationMetadata applicationMetadata = applicationConnectionResult.getApplicationMetadata();
                                            String sessionId = applicationConnectionResult.getSessionId();
                                            String applicationStatus = applicationConnectionResult.getApplicationStatus();
                                            boolean wasLaunched = applicationConnectionResult.getWasLaunched();
    
                                            mApplicationStarted = true;
                                            reconnectChannels( null );
                                        }
                                    }
                                }
                        );
                    } catch ( Exception e ) {
    
                    }
                }
            }
    
            @Override
            public void onConnectionSuspended(int i) {
                mWaitingForReconnect = true;
            }
        }
    
        private void reconnectChannels( Bundle hint ) {
            if( ( hint != null ) && hint.getBoolean( Cast.EXTRA_APP_NO_LONGER_RUNNING ) ) {
                //Log.e( TAG, "App is no longer running" );
                teardown();
            } else {
                try {
                    Cast.CastApi.setMessageReceivedCallbacks( mApiClient, mRemoteMediaPlayer.getNamespace(), mRemoteMediaPlayer );
                } catch( IOException e ) {
                    //Log.e( TAG, "Exception while creating media channel ", e );
                } catch( NullPointerException e ) {
                    //Log.e( TAG, "Something wasn't reinitialized for reconnectChannels" );
                }
            }
        }
    
        private class ConnectionFailedListener implements GoogleApiClient.OnConnectionFailedListener {
            @Override
            public void onConnectionFailed( ConnectionResult connectionResult ) {
                teardown();
            }
        }
    
        @Override
        public boolean onCreateOptionsMenu( Menu menu ) {
            super.onCreateOptionsMenu( menu );
            getMenuInflater().inflate( R.menu.main, menu );
            MenuItem mediaRouteMenuItem = menu.findItem( R.id.media_route_menu_item );
            MediaRouteActionProvider mediaRouteActionProvider = (MediaRouteActionProvider) MenuItemCompat.getActionProvider( mediaRouteMenuItem );
            mediaRouteActionProvider.setRouteSelector( mMediaRouteSelector );
            return true;
        }
    
        private void teardown() {
            if( mApiClient != null ) {
                if( mApplicationStarted ) {
                    try {
                        Cast.CastApi.stopApplication( mApiClient );
                        if( mRemoteMediaPlayer != null ) {
                            Cast.CastApi.removeMessageReceivedCallbacks( mApiClient, mRemoteMediaPlayer.getNamespace() );
                            mRemoteMediaPlayer = null;
                        }
                    } catch( IOException e ) {
                        //Log.e( TAG, "Exception while removing application " + e );
                    }
                    mApplicationStarted = false;
                }
                if( mApiClient.isConnected() )
                    mApiClient.disconnect();
                mApiClient = null;
            }
            mSelectedDevice = null;
            mVideoIsLoaded = false;
        }
    
    
        @Override
        public void onDestroy() {
            teardown();
            super.onDestroy();
        }
    
    }
    

    Thanks

Tags: android

View All PostsLeave a Comment
comments powered by Disqus

Mobile Applications

Video Content

Bigdata & NoSQL

SaaS Applications

Miscellaneous

Archives


Alexa Certified Site Stats for www.oodlestechnologies.com