Android - 通过自定义应用将屏幕投射到 chromecast

Android - cast screen to chromecast via custom app

我需要对 Chromecast 应用程序执行相同的操作 (com.google.android.apps.chromecast.app) "Mirror screen" 功能:

按应用要求 select chromecast 设备进行流式传输的自定义按钮,然后启动屏幕镜像到 selected chromecast 设备。

实际上,此功能并未在任何地方记录。我必须使用 Presentation class 吗?

阅读 Chromecast 应用程序的日志我发现了以下接收器应用程序 ID:

app id E8C28D3C
app name Backdrop

app id 674A0243
app name Screen Mirroring

我该怎么做?

这是我的代码:

    public class MainActivity extends ActionBarActivity
{

    private MediaRouter mMediaRouter;
    private MediaRouteSelector mMediaRouteSelector;
    private android.support.v7.media.MediaRouter.Callback mMediaRouterCallback;
    private CastDevice mSelectedDevice;
    private GoogleApiClient mApiClient;
    private Cast.Listener mCastClientListener;
    private ConnectionCallbacks mConnectionCallbacks;
    private ConnectionFailedListener mConnectionFailedListener;
    private boolean mWaitingForReconnect;
    private boolean mApplicationStarted;
    private String mSessionId;
    private DemoPresentation mPresentation;

    private final static String TAG = "CAST-APP";
    private String mAppID = "AE85BA70";
    private String mirroringAppID="674A0243";

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mMediaRouter = MediaRouter.getInstance(getApplicationContext());
        mMediaRouteSelector = new MediaRouteSelector.Builder()
                //.addControlCategory(MediaControlIntent.CATEGORY_LIVE_AUDIO)
                //.addControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO)
                //.addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)
                //.addControlCategory(CastMediaControlIntent.categoryForCast(CastMediaControlIntent.DEFAULT_MEDIA_RECEIVER_APPLICATION_ID))
                .addControlCategory(CastMediaControlIntent.categoryForCast(mirroringAppID))
                .build();

        mMediaRouterCallback = new MyMediaRouterCallback();

        /*MediaRouteButton btn = (MediaRouteButton) findViewById(R.id.mediabutton);
        btn.setRouteSelector(mMediaRouteSelector);*/
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        super.onCreateOptionsMenu(menu);

        getMenuInflater().inflate(R.menu.menu_main, menu);

        MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item);

        MediaRouteActionProvider mediaRouteActionProvider =
                (MediaRouteActionProvider) MenuItemCompat.getActionProvider(mediaRouteMenuItem);

        mediaRouteActionProvider.setRouteSelector(mMediaRouteSelector);

        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item)
    {
        int id = item.getItemId();
        return super.onOptionsItemSelected(item);
    }

    @Override
    protected void onResume() {
        super.onResume();
        mMediaRouter.addCallback(mMediaRouteSelector, mMediaRouterCallback,
                                 MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
    }

    @Override
    protected void onPause() {
        if (isFinishing()) {
            mMediaRouter.removeCallback(mMediaRouterCallback);
        }
        super.onPause();
    }
/*
    @Override
    protected void onStart() {
        super.onStart();
        mMediaRouter.addCallback(mMediaRouteSelector, mMediaRouterCallback,
                                 MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
    }

    @Override
    protected void onStop() {
        mMediaRouter.removeCallback(mMediaRouterCallback);
        super.onStop();
    }
*/

    private class MyMediaRouterCallback extends MediaRouter.Callback {

        @Override
        public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo info) {
            try
            {
                mSelectedDevice = CastDevice.getFromBundle(info.getExtras());
                String routeId = info.getId();

                mCastClientListener = new Cast.Listener()
                {
                    @Override
                    public void onApplicationStatusChanged()
                    {
                        if (mApiClient != null)
                        {
                            Log.d(TAG, "onApplicationStatusChanged: "
                                    + Cast.CastApi.getApplicationStatus(mApiClient));

                            //updatePresentation();

                        }
                    }

                    @Override
                    public void onVolumeChanged()
                    {
                        if (mApiClient != null)
                        {
                            Log.d(TAG, "onVolumeChanged: " + Cast.CastApi.getVolume(mApiClient));
                        }
                    }

                    @Override
                    public void onApplicationDisconnected(int errorCode)
                    {
                        teardown();
                    }
                };

                mConnectionCallbacks = new ConnectionCallbacks();
                mConnectionFailedListener = new ConnectionFailedListener();

                Cast.CastOptions.Builder apiOptionsBuilder = Cast.CastOptions
                        .builder(mSelectedDevice, mCastClientListener);

                mApiClient = new GoogleApiClient.Builder(getApplication())
                        .addApi(Cast.API, apiOptionsBuilder.build())
                        .addConnectionCallbacks(mConnectionCallbacks)
                        .addOnConnectionFailedListener(mConnectionFailedListener)
                        .build();

                mApiClient.connect();

            } catch (Exception e) {
                Log.d(TAG, "onRouteSelected " + e.getMessage());
            }

        }

        @Override
        public void onRouteUnselected(MediaRouter router, MediaRouter.RouteInfo info) {
            Log.d(TAG, "onRouteUnselected: info=" + info);
            teardown();
            //updatePresentation();
            mSelectedDevice = null;
        }

        @Override
        public void onRoutePresentationDisplayChanged(MediaRouter router, MediaRouter.RouteInfo info) {

            //updatePresentation();
        }
    }

    private void showPresentation()
    {
        DisplayManager displayManager = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);
        Display[] presentationDisplays = displayManager.getDisplays();

        Log.d("showPresentation", "Displays: " + String.valueOf(presentationDisplays.length));

        if (presentationDisplays.length > 0) {

            Log.d("showPresentation", "Display : " + presentationDisplays[0].getName());

            Display display = presentationDisplays[0];
            mPresentation = new DemoPresentation(this, display);
            mPresentation.show();
        }



        //updatePresentation();
    }

    private class ConnectionCallbacks implements
            GoogleApiClient.ConnectionCallbacks {
        @Override
        public void onConnected(Bundle connectionHint) {
            if (mWaitingForReconnect) {
                mWaitingForReconnect = false;
                //reconnectChannels();
                if ((connectionHint != null)
                        && connectionHint
                        .getBoolean(Cast.EXTRA_APP_NO_LONGER_RUNNING)) {
                    Log.d(TAG, "App  is no longer running");
                    teardown();
                }
            } else {
                try {
                    Cast.CastApi.launchApplication(mApiClient, mirroringAppID, false)
                            .setResultCallback(
                                    new ResultCallback<Cast.ApplicationConnectionResult>() {
                                        @Override
                                        public void onResult(Cast.ApplicationConnectionResult result) {
                                            Status status = result.getStatus();
                                            if (status.isSuccess()) {
                                                ApplicationMetadata applicationMetadata =
                                                        result.getApplicationMetadata();
                                                mSessionId = result.getSessionId();
                                                String applicationStatus = result.getApplicationStatus();
                                                boolean wasLaunched = result.getWasLaunched();

                                                mApplicationStarted = true;

                                            } else {
                                                teardown();
                                            }
                                        }
                                    });

                } catch (Exception e) {
                    Log.e(TAG, "Failed to launch application", e);
                }
            }
        }

        @Override
        public void onConnectionSuspended(int cause) {
            mWaitingForReconnect = true;
        }
    }

    private class ConnectionFailedListener implements
            GoogleApiClient.OnConnectionFailedListener {
        @Override
        public void onConnectionFailed(ConnectionResult result) {
            teardown();
        }
    }

    private void teardown() {
        Log.d(TAG, "teardown");
        if (mApiClient != null) {
            if (mApplicationStarted) {
                if (mApiClient.isConnected()  || mApiClient.isConnecting()) {
                    try {
                        Cast.CastApi.stopApplication(mApiClient, mSessionId);

                    } catch (Exception e) {
                        Log.e(TAG, "Exception while removing channel", e);
                    }
                    mApiClient.disconnect();
                }
                mApplicationStarted = false;
            }
            mApiClient = null;
        }
        mSelectedDevice = null;
        mWaitingForReconnect = false;
        mSessionId = null;
    }
}

你不能从你自己的应用程序中做到这一点,目前没有可供开发人员从他们的应用程序中启动投射镜像的 API,它应该由用户手动完成;这在未来可能会改变,但这是当前状态。

看来你只要不设置任何自定义Presentation screen就默认进行镜像:

https://developer.android.com/reference/android/media/MediaRouter.html#ROUTE_TYPE_LIVE_VIDEO