使用CastCompanionLibrary简单显示图像的示例

时间:2014-03-01 23:13:21

标签: android google-cast

我正在寻找在Android中将图像转换为chromecast的示例。奇怪的是,googlecast样本库中似乎没有这个内容。有没有人有这个简单的实现?我基本上想点击我的Android设备上我的应用程序的照片库中的图像,并将其投射到屏幕上。 一方面的问题是,图像是否需要在网址上?或者是否可以将图像流式传输到设备?我提前感谢你的帮助。

3 个答案:

答案 0 :(得分:4)

我在没有CastCompanionLibrary的情况下解决了这个问题,但基于google的CastHelloText-android示例。基本上我做的是:

  1. 将图像编码为base64字符串,并将其作为消息发送给自定义接收器
  2. 修改样本的接收器以接收base64字符串并将其设置为图像源。
  3. upload and register我的接收者并让应用程序使用生成的应用程序ID
  4. 这是接收者的代码:

    <!DOCTYPE html>
    <html>
      <head>
        <style>
          img#androidImage {
            height:auto;
            width:100%;
          }
        </style>
        <title>Cast Hello Text</title>
      </head>
      <body>
        <img id="androidImage" src="" />
        <script type="text/javascript" src="//www.gstatic.com/cast/sdk/libs/receiver/2.0.0/cast_receiver.js"></script>
        <script type="text/javascript">
          window.onload = function() {
            cast.receiver.logger.setLevelValue(0);
            window.castReceiverManager = cast.receiver.CastReceiverManager.getInstance();
            console.log('Starting Receiver Manager');
    
            // handler for the 'ready' event
            castReceiverManager.onReady = function(event) {
              console.log('Received Ready event: ' + JSON.stringify(event.data));
              window.castReceiverManager.setApplicationState("Application status is ready...");
            };
    
            // handler for 'senderconnected' event
            castReceiverManager.onSenderConnected = function(event) {
              console.log('Received Sender Connected event: ' + event.data);
              console.log(window.castReceiverManager.getSender(event.data).userAgent);
            };
    
            // handler for 'senderdisconnected' event
            castReceiverManager.onSenderDisconnected = function(event) {
              console.log('Received Sender Disconnected event: ' + event.data);
              if (window.castReceiverManager.getSenders().length == 0) {
                window.close();
              }
            };
    
            // handler for 'systemvolumechanged' event
            castReceiverManager.onSystemVolumeChanged = function(event) {
              console.log('Received System Volume Changed event: ' + event.data['level'] + ' ' +
                  event.data['muted']);
            };
    
            // create a CastMessageBus to handle messages for a custom namespace
            window.messageBus =
              window.castReceiverManager.getCastMessageBus(
                  'urn:x-cast:com.google.cast.sample.helloworld');
    
            // handler for the CastMessageBus message event
            window.messageBus.onMessage = function(event) {
              console.log('Message recieved');
    
              var obj = JSON.parse(event.data)
    
              console.log('Message type: ' + obj.type);
              if (obj.type == "text") {
                console.log('Skipping message: ' + obj.data);
              }
    
              if (obj.type == "image") {
                var source = 'data:image/png;base64,'.concat(obj.data)
                displayImage(source);
              }
    
              // inform all senders on the CastMessageBus of the incoming message event
              // sender message listener will be invoked
              window.messageBus.send(event.senderId, event.data);
            }
    
            // initialize the CastReceiverManager with an application status message
            window.castReceiverManager.start({statusText: "Application is starting"});
            console.log('Receiver Manager started');
          };
    
    
          function displayImage(source) {
            console.log('received image');
            document.getElementById("androidImage").src=source;
            window.castReceiverManager.setApplicationState('image source changed');
          };
    
        </script>
      </body>
    </html>
    

    以下是修改后的MainActivity.java代码。注册接收器应用程序后,不要忘记修改string.xml中的app_id。

    2注:

    • 发送的消息包装在JSON对象中,因此我可以过滤掉 短信。
    • 此处未定义ENCODED_IMAGE_STRING变量 例如,您必须自己找到一个图像并将其转换为base64字符串。

    MainActivity.java:

    package com.example.casthelloworld;
    
    import java.io.IOException;
    import java.util.ArrayList;
    
    import android.content.Intent;
    import android.graphics.drawable.ColorDrawable;
    import android.os.Bundle;
    import android.speech.RecognizerIntent;
    import android.support.v4.view.MenuItemCompat;
    import android.support.v7.app.ActionBar;
    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.util.Log;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.Toast;
    
    import com.google.android.gms.cast.ApplicationMetadata;
    import com.google.android.gms.cast.Cast;
    import com.google.android.gms.cast.Cast.ApplicationConnectionResult;
    import com.google.android.gms.cast.Cast.MessageReceivedCallback;
    import com.google.android.gms.cast.CastDevice;
    import com.google.android.gms.cast.CastMediaControlIntent;
    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;
    /**
     * Main activity to send messages to the receiver.
     */
    public class MainActivity extends ActionBarActivity {
    
        private static final String TAG = MainActivity.class.getSimpleName();
    
        private static final int REQUEST_CODE = 1;
    
        private MediaRouter mMediaRouter;
        private MediaRouteSelector mMediaRouteSelector;
        private MediaRouter.Callback mMediaRouterCallback;
        private CastDevice mSelectedDevice;
        private GoogleApiClient mApiClient;
        private Cast.Listener mCastListener;
        private ConnectionCallbacks mConnectionCallbacks;
        private ConnectionFailedListener mConnectionFailedListener;
        private HelloWorldChannel mHelloWorldChannel;
        private boolean mApplicationStarted;
        private boolean mWaitingForReconnect;
        private String mSessionId;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            ActionBar actionBar = getSupportActionBar();
            actionBar.setBackgroundDrawable(new ColorDrawable(
                    android.R.color.transparent));
    
            // When the user clicks on the button, use Android voice recognition to
            // get text
            Button voiceButton = (Button) findViewById(R.id.voiceButton);
            voiceButton.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    startVoiceRecognitionActivity();
                }
            });
    
    
            // When the user clicks on the button, use Android voice recognition to
            // get text
            Button yarrButton = (Button) findViewById(R.id.tmpButton);
            yarrButton.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    castImage();
                }
            });
    
            // Configure Cast device discovery
            mMediaRouter = MediaRouter.getInstance(getApplicationContext());
            mMediaRouteSelector = new MediaRouteSelector.Builder()
                    .addControlCategory(
                            CastMediaControlIntent.categoryForCast(getResources()
                                    .getString(R.string.app_id))).build();
            mMediaRouterCallback = new MyMediaRouterCallback();
        }
    
        private void castImage()
        {
            Log.d(TAG, "castImage()");
    
            String image_string = createJsonMessage(MessageType.image, ENCODED_IMAGE_STRING);
    
            sendMessage(image_string);
        }
    
        /**
         * Android voice recognition
         */
        private void startVoiceRecognitionActivity() {
            Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
            intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
                    RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
            intent.putExtra(RecognizerIntent.EXTRA_PROMPT,
                    getString(R.string.message_to_cast));
            startActivityForResult(intent, REQUEST_CODE);
        }
    
        /*
         * Handle the voice recognition response
         * 
         * @see android.support.v4.app.FragmentActivity#onActivityResult(int, int,
         * android.content.Intent)
         */
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
                ArrayList<String> matches = data
                        .getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
                if (matches.size() > 0) {
                    Log.d(TAG, matches.get(0));
                    String message = createJsonMessage(MessageType.text, matches.get(0));
                    sendMessage(message);
                }
            }
            super.onActivityResult(requestCode, resultCode, data);
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            // Start media router discovery
            mMediaRouter.addCallback(mMediaRouteSelector, mMediaRouterCallback,
                    MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
        }
    
        @Override
        protected void onPause() {
            if (isFinishing()) {
                // End media router discovery
                mMediaRouter.removeCallback(mMediaRouterCallback);
            }
            super.onPause();
        }
    
        @Override
        public void onDestroy() {
            teardown();
            super.onDestroy();
        }
    
        @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);
            // Set the MediaRouteActionProvider selector for device discovery.
            mediaRouteActionProvider.setRouteSelector(mMediaRouteSelector);
            return true;
        }
    
        /**
         * Callback for MediaRouter events
         */
        private class MyMediaRouterCallback extends MediaRouter.Callback {
    
            @Override
            public void onRouteSelected(MediaRouter router, RouteInfo info) {
                Log.d(TAG, "onRouteSelected");
                // Handle the user route selection.
                mSelectedDevice = CastDevice.getFromBundle(info.getExtras());
    
                launchReceiver();
            }
    
            @Override
            public void onRouteUnselected(MediaRouter router, RouteInfo info) {
                Log.d(TAG, "onRouteUnselected: info=" + info);
                teardown();
                mSelectedDevice = null;
            }
        }
    
        /**
         * Start the receiver app
         */
        private void launchReceiver() {
            try {
                mCastListener = new Cast.Listener() {
    
                    @Override
                    public void onApplicationDisconnected(int errorCode) {
                        Log.d(TAG, "application has stopped");
                        teardown();
                    }
    
                };
                // Connect to Google Play services
                mConnectionCallbacks = new ConnectionCallbacks();
                mConnectionFailedListener = new ConnectionFailedListener();
                Cast.CastOptions.Builder apiOptionsBuilder = Cast.CastOptions
                        .builder(mSelectedDevice, mCastListener);
                mApiClient = new GoogleApiClient.Builder(this)
                        .addApi(Cast.API, apiOptionsBuilder.build())
                        .addConnectionCallbacks(mConnectionCallbacks)
                        .addOnConnectionFailedListener(mConnectionFailedListener)
                        .build();
    
                mApiClient.connect();
            } catch (Exception e) {
                Log.e(TAG, "Failed launchReceiver", e);
            }
        }
    
        /**
         * Google Play services callbacks
         */
        private class ConnectionCallbacks implements
                GoogleApiClient.ConnectionCallbacks {
            @Override
            public void onConnected(Bundle connectionHint) {
                Log.d(TAG, "onConnected");
    
                if (mApiClient == null) {
                    // We got disconnected while this runnable was pending
                    // execution.
                    return;
                }
    
                try {
                    if (mWaitingForReconnect) {
                        mWaitingForReconnect = false;
    
                        // Check if the receiver app is still running
                        if ((connectionHint != null)
                                && connectionHint
                                        .getBoolean(Cast.EXTRA_APP_NO_LONGER_RUNNING)) {
                            Log.d(TAG, "App  is no longer running");
                            teardown();
                        } else {
                            // Re-create the custom message channel
                            try {
                                Cast.CastApi.setMessageReceivedCallbacks(
                                        mApiClient,
                                        mHelloWorldChannel.getNamespace(),
                                        mHelloWorldChannel);
                            } catch (IOException e) {
                                Log.e(TAG, "Exception while creating channel", e);
                            }
                        }
                    } else {
                        // Launch the receiver app
                        Cast.CastApi
                                .launchApplication(mApiClient,
                                        getString(R.string.app_id), false)
                                .setResultCallback(
                                        new ResultCallback<Cast.ApplicationConnectionResult>() {
                                            @Override
                                            public void onResult(
                                                    ApplicationConnectionResult result) {
                                                Status status = result.getStatus();
                                                Log.d(TAG,
                                                        "ApplicationConnectionResultCallback.onResult: statusCode "
                                                                + status.getStatusCode());
                                                if (status.isSuccess()) {
                                                    ApplicationMetadata applicationMetadata = result
                                                            .getApplicationMetadata();
                                                    mSessionId = result
                                                            .getSessionId();
                                                    String applicationStatus = result
                                                            .getApplicationStatus();
                                                    boolean wasLaunched = result
                                                            .getWasLaunched();
                                                    Log.d(TAG,
                                                            "application name: "
                                                                    + applicationMetadata
                                                                            .getName()
                                                                    + ", status: "
                                                                    + applicationStatus
                                                                    + ", sessionId: "
                                                                    + mSessionId
                                                                    + ", wasLaunched: "
                                                                    + wasLaunched);
                                                    mApplicationStarted = true;
    
                                                    // Create the custom message
                                                    // channel
                                                    mHelloWorldChannel = new HelloWorldChannel();
                                                    try {
                                                        Cast.CastApi
                                                                .setMessageReceivedCallbacks(
                                                                        mApiClient,
                                                                        mHelloWorldChannel
                                                                                .getNamespace(),
                                                                        mHelloWorldChannel);
                                                    } catch (IOException e) {
                                                        Log.e(TAG,
                                                                "Exception while creating channel",
                                                                e);
                                                    }
    
                                                    // set the initial instructions
                                                    // on the receiver
                                                    String message = createJsonMessage(MessageType.text, getString(R.string.instructions));
                                                    sendMessage(message);
                                                } else {
                                                    Log.e(TAG,
                                                            "application could not launch");
                                                    teardown();
                                                }
                                            }
                                        });
                    }
                } catch (Exception e) {
                    Log.e(TAG, "Failed to launch application", e);
                }
            }
    
            @Override
            public void onConnectionSuspended(int cause) {
                Log.d(TAG, "onConnectionSuspended");
                mWaitingForReconnect = true;
            }
        }
    
        /**
         * Google Play services callbacks
         */
        private class ConnectionFailedListener implements
                GoogleApiClient.OnConnectionFailedListener {
            @Override
            public void onConnectionFailed(ConnectionResult result) {
                Log.e(TAG, "onConnectionFailed ");
    
                teardown();
            }
        }
    
        /**
         * Tear down the connection to the receiver
         */
        private void teardown() {
            Log.d(TAG, "teardown");
            if (mApiClient != null) {
                if (mApplicationStarted) {
                    if (mApiClient.isConnected()  || mApiClient.isConnecting()) {
                        try {
                            Cast.CastApi.stopApplication(mApiClient, mSessionId);
                            if (mHelloWorldChannel != null) {
                                Cast.CastApi.removeMessageReceivedCallbacks(
                                        mApiClient,
                                        mHelloWorldChannel.getNamespace());
                                mHelloWorldChannel = null;
                            }
                        } catch (IOException e) {
                            Log.e(TAG, "Exception while removing channel", e);
                        }
                        mApiClient.disconnect();
                    }
                    mApplicationStarted = false;
                }
                mApiClient = null;
            }
            mSelectedDevice = null;
            mWaitingForReconnect = false;
            mSessionId = null;
        }
    
        /**
         * Send a text message to the receiver
         * 
         * @param message
         */
        private void sendMessage(String message) {
            if (mApiClient != null && mHelloWorldChannel != null) {
                try {
                    Cast.CastApi.sendMessage(mApiClient,
                            mHelloWorldChannel.getNamespace(), message)
                            .setResultCallback(new ResultCallback<Status>() {
                                @Override
                                public void onResult(Status result) {
                                    if (!result.isSuccess()) {
                                        Log.e(TAG, "Sending message failed");
                                    }
                                }
                            });
                } catch (Exception e) {
                    Log.e(TAG, "Exception while sending message", e);
                }
            } else {
                Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT)
                        .show();
            }
        }
    
        /**
         * Custom message channel
         */
        class HelloWorldChannel implements MessageReceivedCallback {
    
            /**
             * @return custom namespace
             */
            public String getNamespace() {
                return getString(R.string.namespace);
            }
    
            /*
             * Receive message from the receiver app
             */
            @Override
            public void onMessageReceived(CastDevice castDevice, String namespace,
                    String message) {
                Log.d(TAG, "onMessageReceived: " + message);
            }
    
        }
    
        enum MessageType {
            text,
            image,
        }
    
        public static Bitmap getBitmapFromView(View view) {
            //Define a bitmap with the same size as the view
            Bitmap returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),Bitmap.Config.ARGB_8888);
            //Bind a canvas to it
            Canvas canvas = new Canvas(returnedBitmap);
            //Get the view's background
            Drawable bgDrawable =view.getBackground();
            if (bgDrawable!=null)
                //has background drawable, then draw it on the canvas
                bgDrawable.draw(canvas);
            else
                //does not have background drawable, then draw white background on the canvas
                canvas.drawColor(Color.WHITE);
            // draw the view on the canvas
            view.draw(canvas);
            //return the bitmap
            return returnedBitmap;
        }
    
        private static String createJsonMessage(MessageType type, String message)
        {
            return String.format("{\"type\":\"%s\", \"data\":\"%s\"}", type.toString(), message);
        }
    }
    

答案 1 :(得分:3)

由于Chromecast上的应用程序在网络浏览器中运行,因此您需要使用<img/>标记显示图片。该标记的src属性应指向您要查看的图像,并且必须是网址,因此如果您的图像位于手机的本地存储中,则需要在您的网站中启动一个小型网络服务器移动应用程序,以提供该图像并与接收器通信它应指向的URL(这将是您的服务器为该图像提供服务的URL)。这些都是可行的,你可以使用CastCompanionLibrary,如果你愿意,与你的自定义接收器进行通信;只需使用DataCastManager类而不是VideoCastManager

答案 2 :(得分:2)

我的答案可能会对其他开发人员有所帮助,因为我也没有找到好的解决方案,而是自己完成的。

要通过Google Cast在设备屏幕上从应用程序显示图像,您可以从应用程序创建并启动Web服务器,该服务器将处理具有选定图像名称或URL中ID的http请求。

示例:

public class MyWebServer {

    private Activity activity;
    private static ServerSocket httpServerSocket;
    private static boolean isWebServerSunning;
    public static final String drawableDelimiter = "pic-"

    public MyWebServer(Activity activity) {
        this.activity = activity;
    }

    public void stopWebServer() {
        isWebServerSunning = false;
        try {
            if (httpServerSocket != null) {
                httpServerSocket.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void startWebServer() {
        isWebServerSunning = true;
        Thread webServerThread = new Thread(() -> {
            Socket socket;
            HttpResponseThread httpResponseThread;
            try {
                httpServerSocket = new ServerSocket(5050);
                while (isWebServerSunning) {
                    socket = httpServerSocket.accept();
                    httpResponseThread = new HttpResponseThread(socket);
                    httpResponseThread.start();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        webServerThread.start();
    }

    private class HttpResponseThread extends Thread {

        Socket clientSocket;

        HttpResponseThread(Socket socket) {
            this.clientSocket = socket;
        }

        @Override
        public void run() {
            try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                 OutputStream outputStream = clientSocket.getOutputStream();
            ) {

                String input = bufferedReader.readLine();
                if (input != null && !input.isEmpty() && input.contains("/") && input.contains(" ")) {

                    if (input.contains(drawableDelimiter)) {

                        String imageId = input.substring(input.indexOf("/") + 1, input.lastIndexOf(" ")).trim().split(drawableDelimiter)[1];

                        Bitmap bitmap = BitmapFactory.decodeResource(activity.getResources(), Integer.parseInt(imageId));
                        if (bitmap != null) {
                            ByteArrayOutputStream bitmapBytes = new ByteArrayOutputStream();
                            bitmap.compress(Bitmap.CompressFormat.PNG, 100, bitmapBytes);

                            outputStream.write("HTTP/1.0 200 OK\r\n".getBytes());
                            outputStream.write("Server: Apache/0.8.4\r\n".getBytes());
                            outputStream.write(("Content-Length: " + bitmapBytes.toByteArray().length + "\r\n").getBytes());
                            outputStream.write("\r\n".getBytes());
                            outputStream.write(bitmapBytes.toByteArray());
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

只要在Google Cast可用或停止时启动或停止Web服务器即可。

MyWebServer myWebServer = new MyWebServer(this); // pass your activity here
myWebServer.startWebServer();
myWebServer.stopWebServer();