stream screen to chromecast using Presentation - android

I'm using com.android.support:appcompat-v7:21.0.3 to develop an app that stream the screen to the TV using chromecast.
The problem is that when i retrieve the presentationDisplay it is null!
I'm using default receiver app and it seems that chromecast does not support
MediaControlIntent.CATEGORY_LIVE_VIDEO
This is the code:
private void updatePresentation() {
Log.d(TAG, "updatePresentation()");
MediaRouter.RouteInfo route = mMediaRouter.getSelectedRoute();
Display presentationDisplay = route != null ? route.getPresentationDisplay() : null;
Log.d(TAG, "MediaRouter.RouteIngo: " + route.getName());
if (presentationDisplay != null)
Log.d(TAG, "presentationDisplay " + presentationDisplay.getName());
else if (presentationDisplay == null)
Log.d(TAG, "presentationDisplay is null");
// Dismiss the current presentation if the display has changed.
if (mPresentation != null && mPresentation.getDisplay() != presentationDisplay) {
Log.i(TAG, "Dismissing presentation because the current route no longer "
+ "has a presentation display.");
mPresentation.dismiss();
mPresentation = null;
}
// Show a new presentation if needed.
if (mPresentation == null && presentationDisplay != null) {
Log.i(TAG, "Showing presentation on display: " + presentationDisplay);
mPresentation = new DemoPresentation(this, presentationDisplay);
mPresentation.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog)
{
if (mPresentation != null) mPresentation.dismiss();
}
});
try {
Log.d("mPresentation", "showing");
mPresentation.show();
} catch (WindowManager.InvalidDisplayException ex) {
Log.w(TAG, "Couldn't show presentation! Display was removed in "
+ "the meantime.", ex);
mPresentation = null;
}
}
}

on my own nexus 10 i used Chromecast App to setup the chromecast device and on my nexsus 4 all happened automatically.
No, I am not referring to just the Chromecast app.
Chromecast natively supports the Cast SDK and RemotePlaybackClient. It also supports serving as an external display, which can be used for Presentation. However, the user has to manually go into Settings > Displays > Cast Screen and choose the Chromecast. Then, you will get screen mirroring, and Presentation will work.

Related

Android native webrtc: add video after already connected

I have successfully been running WebRTC in my Android app for a while, using libjingle.so and PeerConnectionClient.java, etc., from Google's code library. However, I am now running into a problem where a user starts a connection as audio only (i.e., an audio call), but then toggles video on. I augmented the existing setVideoEnabled() in PeerConnectionClient as such:
public void setVideoEnabled(final boolean enable) {
executor.execute(new Runnable() {
#Override
public void run() {
renderVideo = enable;
if (localVideoTrack != null) {
localVideoTrack.setEnabled(renderVideo);
} else {
if (renderVideo) {
//AC: create a video track
String cameraDeviceName = VideoCapturerAndroid.getDeviceName(0);
String frontCameraDeviceName =
VideoCapturerAndroid.getNameOfFrontFacingDevice();
if (numberOfCameras > 1 && frontCameraDeviceName != null) {
cameraDeviceName = frontCameraDeviceName;
}
Log.i(TAG, "Opening camera: " + cameraDeviceName);
videoCapturer = VideoCapturerAndroid.create(cameraDeviceName);
if (createVideoTrack(videoCapturer) != null) {
mediaStream.addTrack(localVideoTrack);
localVideoTrack.setEnabled(renderVideo);
peerConnection.addStream(mediaStream);
} else {
Log.d(TAG, "Local video track is still null");
}
} else {
Log.d(TAG, "Local video track is null");
}
}
if (remoteVideoTrack != null) {
remoteVideoTrack.setEnabled(renderVideo);
} else {
Log.d(TAG,"Remote video track is null");
}
}
});
}
This allows me successfully see a local inset of the device's video camera, but it doesn't send the video to the remove client. I thought the peerConnection.addStream() call would do that, but perhaps I am missing something else?
To avoid building an external mechanism of communication between peers that will involve an answer from the second peer that the new stream can be added, you can always start with existing (but sometimes empty) video stream. Now it is just the matter of filling this stream with content when (and if) necessary.

Connecting to existing Google Chromecast Session from Android (for generic remote control)

I am creating a generic Chromecast remote control app. Most of the guts of the app are already created and I've managed to get Chromecast volume control working (by connecting to a Chromecast device along side another app that is casting - YouTube for example).
What I've having difficult with is performing other media commands such as play, pause, seek, etc.
Use case example:
1. User opens YouTube on their android device and starts casting a video.
2. User opens my app and connects to the same Chromecast device.
3. Volume control from my app (works now)
4. Media control (play, pause, etc) (does not yet work)
I found the Cast api reference that explains that you can sendMessage(ApiClient, namespace, message) with media commands; however the "message" (JSON) requires the sessionId of the current application (Youtube in this case). I have tried the following, but the connection to the current application always fails; status.isSuccess() is always false:
Cast.CastApi
.joinApplication(mApiClient)
.setResultCallback(
new ResultCallback<Cast.ApplicationConnectionResult>() {
#Override
public void onResult(
Cast.ApplicationConnectionResult result) {
Status status = result.getStatus();
if (status.isSuccess()) {
ApplicationMetadata applicationMetadata = result
.getApplicationMetadata();
sessionId = result.getSessionId();
String applicationStatus = result
.getApplicationStatus();
boolean wasLaunched = result
.getWasLaunched();
Log.i(TAG,
"Joined Application with sessionId: "
+ sessionId
+ " Application Status: "
+ applicationStatus);
} else {
// teardown();
Log.e(TAG,
"Could not join application: "
+ status.toString());
}
}
});
Is is possible to get the sessionId of an already running cast application from a generic remote control app (like the one I am creating)? If so, am I right in my assumption that I can then perform media commands on the connected Chromecast device using something like this:
JSONObject message = new JSONObject();
message.put("mediaSessionId", sessionId);
message.put("requestId", 9999);
message.put("type", "PAUSE");
Cast.CastApi.sendMessage(mApiClient,
"urn:x-cast:com.google.cast.media", message.toString());
Update:
I have tried the recommendations provided by #Ali Naddaf but unfortunately they are not working. After creating mRemoteMediaPlayer in onCreate, I also do requestStatus(mApiClient) in the onConnected callback (in the ConnectionCallbacks). When I try to .play(mApiClient) I get an IllegalStateException stating that there is no current media session. Also, I tried doing joinApplication and in the callback performed result.getSessionId; which returns null.
A few comments and answers:
You can get the sessionId from the callback of launchApplication or joinApplication; in the "onResult(result)", you can get the sessionId from: result.getSessionId()
YouTube is still not on the official SDK so YMMV, for apps using official SDK, you should be able to use the above approach (most of it)
Why are you trying to set up a message yourself? Why not building a RemoteMediaPlayer and using play/pause that is provided there? Whenever you are working with the media playback through the official channel, always use the RemoteMediaPlayer (don't forget to call requestStatus() on it after creating it).
Yes it is possible , First you have to save sesionId and CastDevice device id
and when remove app from background and again open app please check is there sessionId then call bello line.
Cast.CastApi.joinApplication(apiClient, APP_ID,sid).setResultCallback(connectionResultCallback);
if you get success result then need to implement further process in connectionResultCallback listener.
//Get selected device which you selected before
#Override
public void onRouteAdded(MediaRouter router, MediaRouter.RouteInfo route) {
// Log.d("Route Added", "onRouteAdded");
/* if (router.getRoutes().size() > 1)
Toast.makeText(homeScreenActivity, "'onRouteAdded :: " + router.getRoutes().size() + " -- " + router.getRoutes().get(1).isSelected(), Toast.LENGTH_SHORT).show();
else
Toast.makeText(homeScreenActivity, "'onRouteAdded :: " + router.getRoutes(), Toast.LENGTH_SHORT).show();*/
if (router != null && router.getRoutes() != null && router.getRoutes().size() > 1) {
// Show the button when a device is discovered.
// Toast.makeText(homeScreenActivity, "'onRouteAdded :: " + router.getRoutes().size() + " -- " + router.getRoutes().get(1).isSelected(), Toast.LENGTH_SHORT).show();
mMediaRouteButton.setVisibility(View.VISIBLE);
titleLayout.setVisibility(View.GONE);
castName.setVisibility(View.VISIBLE);
selectedDevice = CastDevice.getFromBundle(route.getExtras());
routeInfoArrayList = router.getRoutes();
titleLayout.setVisibility(View.GONE);
if (!isCastConnected) {
String deid = MyPref.getInstance(homeScreenActivity).readPrefs(MyPref.CAST_DEVICE_ID);
for (int i = 0; i < routeInfoArrayList.size(); i++) {
if (routeInfoArrayList.get(i).getExtras() != null && CastDevice.getFromBundle(routeInfoArrayList.get(i).getExtras()).getDeviceId().equalsIgnoreCase(deid)) {
selectedDevice = CastDevice.getFromBundle(routeInfoArrayList.get(i).getExtras());
routeInfoArrayList.get(i).select();
ReSelectedDevice(selectedDevice, routeInfoArrayList.get(i).getName());
break;
}
}
}
}
}
//Reconnect google Api Client
public void reConnectGoogleApiClient() {
if (apiClient == null) {
Cast.CastOptions apiOptions = new
Cast.CastOptions.Builder(selectedDevice, castClientListener).build();
apiClient = new GoogleApiClient.Builder(this)
.addApi(Cast.API, apiOptions)
.addConnectionCallbacks(reconnectionCallback)
.addOnConnectionFailedListener(connectionFailedListener)
.build();
apiClient.connect();
}
}
// join Application
private final GoogleApiClient.ConnectionCallbacks reconnectionCallback = new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(Bundle bundle) {
// Toast.makeText(homeScreenActivity, "" + isDeviceSelected(), Toast.LENGTH_SHORT).show();
try {
String sid = MyPref.getInstance(homeScreenActivity).readPrefs(MyPref.CAST_SESSION_ID);
String deid = MyPref.getInstance(homeScreenActivity).readPrefs(MyPref.CAST_DEVICE_ID);
if (sid != null && deid != null && sid.length() > 0 && deid.length() > 0)
Cast.CastApi.joinApplication(apiClient, APP_ID, sid).setResultCallback(connectionResultCallback);
isApiConnected = true;
} catch (Exception e) {
}
}
#Override
public void onConnectionSuspended(int i) {
isCastConnected = false;
isApiConnected = false;
}
};

Google Cast SDK - getting a network timeout a few seconds after opening a session

This is my openSession method, based on the sample's:
Log.d("asdf", "Beginning session with context: " + mCastContext);
Log.d("asdf", "The session to begin: " + mSession);
mSession.setListener(new com.google.cast.ApplicationSession.Listener() {
#Override
public void onSessionStarted(ApplicationMetadata appMetadata) {
Log.d("asdf", "Getting channel after session start");
ApplicationChannel channel = mSession.getChannel();
if (channel == null) {
Log.e("asdf", "channel = null");
return;
}
Log.d("asdf", "Creating and attaching Message Stream");
mMessageStream = new MediaProtocolMessageStream();
channel.attachMessageStream(mMessageStream);
if (mMessageStream.getPlayerState() == null) {
if (mMedia != null) {
loadMedia(mMedia);
}
} else {
Log.d("asdf", "Found player already running");
// updateStatus(); TODO
}
}
It works fine, and I can push content to Leapcast (emulator) in a short window of time, usually about 6 seconds.
After that 6 seconds, however, I get this:
Log: onEnded failed to connect channel: network I/O timeout
Called from onSessionEnded.
What exactly is ending my session? Is it just an issue with Leapcast? Do I need to do some sort of keep-alive?

Android Player Error (-38,0)

i made a stream program to play an ad + audio + ad. i play first ad fine , then i switch to the audio which fine then i fail at playing the last ad and i get Error(38,0). i checked that i have set data source,onPrepareListener and i tried every thing i can found so far but still getting this error on android 4.1.1
I get error after my method MPStarting , i do not even reach the onPrepared method only for final ad.if there is any info u need more plz let me know thanks.
here is the part of code which is related
MPStarting(Track)
{ try
{
if (_playlist !=null && _playlist.GetCurrent() != null)
{
Episode ep = (Episode) _playlist.GetCurrent();
_player = new MediaPlayer();
AdsInfo startAd = ep.getAdWithType(PlayTime.start_ad);
AdsInfo endAd = ep.getAdWithType(PlayTime.end_ad);
if(currAudio == null && startAd != null)
currAudio = startAd;
else if(currAudio == startAd )
currAudio = ep;
else if (currAudio instanceof Episode && endAd != null)
currAudio = ep.getAdWithType(PlayTime.end_ad);
}
if(_player != null)
{
_player.setDataSource(dataSource);
_player.setOnPreparedListener(this);
_player.setOnCompletionListener(this);
_player.setOnBufferingUpdateListener(this);
_player.setOnSeekCompleteListener(this);
_player.setOnErrorListener(this);
_player.prepareAsync();
}
catch (Exception e)
{
Log.i("mpcPlayer","MPStarting "+ e.getLocalizedMessage());
}
}
}
#Override
public void onCompletion(MediaPlayer mp)
{
//here i check on current playing
//i always stop player if it is playing ,reset,release and make player = null
// then i call MPStarting and i send the current audio then return
}
I think i found my problem ,i was calling sometimes getCurrentPosition() it seems player was not ready at that time.i guess this error is about calling a method sometimes while player not in right state.

JellyBean external display not found with MediaRouter or DisplayManager

I am trying to use Presenter feature in JellyBean to show custom graphics on additional large screen. I am connected with MHL compliant HDMI adapter (microUSB -> HDMI). Piece of my code trying to detect external display is below. For some reason - I do get output on my external monitor but DisplayManager won't detect external display. I wonder if this has to do with adapter or it would be the case if I connected phone to external display with HDMI cable directly?
My logcat: http://postimg.org/image/sloflge1b/
My code piece:
#SuppressLint("NewApi")
private void updatePresentation() {
// Get the current route and its presentation display.
Log.d(EXTRA_DISPLAY_TAG, "Inside updatePresentation() call...");
MediaRouter.RouteInfo route = mediaRouter.getSelectedRoute(MediaRouter.ROUTE_TYPE_LIVE_VIDEO);
Log.d(EXTRA_DISPLAY_TAG, "Route name: " + route.getName() + " , route status: " + route.getStatus());
Display externalDisplay = null;
if(route != null && route.getName().equals("HDMI")){
externalDisplay = route.getPresentationDisplay();
if(externalDisplay == null){ //Maybe not ready...
Log.d(EXTRA_DISPLAY_TAG, "Waiting for external display to become ready...");
SystemClock.sleep(2000);
DisplayManager displayManager = (DisplayManager)getSystemService(DISPLAY_SERVICE);
Display[] presentationDisplays = displayManager.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION);
if(null == presentationDisplays || presentationDisplays.length == 0){
Log.d(EXTRA_DISPLAY_TAG, "Didn't find any presentation displays by category...");
}else{
externalDisplay = presentationDisplays[0]; //OK: Take first
}
//Try to manually select display...
if(externalDisplay == null){
Display[] allDisplays = displayManager.getDisplays();
for(int i=0; i<allDisplays.length; i++){
Log.d(EXTRA_DISPLAY_TAG, "Detected display "+(i+1)+ " : " + allDisplays[i].getName());
}
//externalDisplay = allDisplays[0]; //FIXME: Take by some criteria...
}
}
}
if(externalDisplay != null){
Log.i(EXTRA_DISPLAY_TAG, "Detected external display...");
Point size = new Point();
externalDisplay.getSize(size);
int width = size.x;
int height = size.y;
Log.i(EXTRA_DISPLAY_TAG, "External display resolution: " + width + "px x " + height + "px");
}
// Dismiss current presentation if display changes
if(quantumPresentation != null && quantumPresentation.getDisplay() != externalDisplay){
Log.i(EXTRA_DISPLAY_TAG, "Leaving presentation because current route no longer has a presentation display.");
quantumPresentation.dismiss();
quantumPresentation = null;
}
// Show new presentation if needed
if(quantumPresentation == null && externalDisplay != null) {
Log.i(EXTRA_DISPLAY_TAG, "Showing presentation on display: " + externalDisplay);
quantumPresentation = new QuantumPresentation(this, externalDisplay);
quantumPresentation.setOnDismissListener(onPresentationDismissListener);
try{
Log.i(EXTRA_DISPLAY_TAG, "Starting additional display presentation...");
quantumPresentation.show();
} catch (WindowManager.InvalidDisplayException ex){
Log.w(EXTRA_DISPLAY_TAG, "Couldn't show presentation! External display was removed in the meantime!", ex);
quantumPresentation = null;
}
}
// Update the contents playing in activity...
updateContents();
}
The Galaxy Nexus does not support multiple independent displays, as has been reported: https://code.google.com/p/android/issues/detail?id=42509

Categories

Resources