Chromcast Remote player seek to resume at seek position 0 when using nanohttpd server. Main issue getting when I seek into video player in device its working fine but on TV seek-bar set at 0 position and music stat at beginning.
When to call mRemoteMediaPlayer.seek() in onSeekChanged() getting result success but on TV seek-bar set at 0 position and music stat at beginning.
public class webserver extends NanoHTTPD {
FileInputStream fileInputStream;
public webserver(){
super(8080);
}
#Override
public Response serve(String uri, Method method, Map<String, String> header,Map<String, String> parameters, Map<String, String> files) {
String mediasend=" ";
long size=0;
FileInputStream fis = null;
try {
fis = new FileInputStream(path);
//byte[] buffer = new byte[(int) fis.getChannel().size()];
size=fis.getChannel().size();
} catch (Exception e) {
e.printStackTrace();
}
switch(mediatype){
case "photo":
mediasend="image/jpeg";
break;
case "audio":
mediasend="audio/mp3";
break;
case "video":
mediasend="video/mp4";
break;
}
return new NanoHTTPD.Response(com.castoffline.castActivity.NanoHTTPD.Response.Status.OK,mediasend,fis,size);
}
}
Cast connection code
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();
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;
mRemoteMediaPlayer = new RemoteMediaPlayer();
/*
* Identify the mediatype and send the metadata details to media info
*/
switch(mediatype)
{
case "audio" : mediaMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MUSIC_TRACK);
mediaMetadata.putString(MediaMetadata.KEY_TITLE, "MY MUSIC TRACK"+": "+audioTitle);
mediaMetadata.putString(MediaMetadata.KEY_ARTIST,audioArtist);
mediaMetadata.addImage(new WebImage(Uri.parse("https://www.googledrive.com/host/0B61ekPEN_94sZ21mcnQtbVU2RHM/media.png")));
mediaInfo = new MediaInfo.Builder(ipdevice).setContentType(mimetype).setStreamType(MediaInfo.STREAM_TYPE_BUFFERED).setMetadata(mediaMetadata).build();
break;
case "video" : mediaMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE);
mediaMetadata.addImage(new WebImage(Uri.parse("https://www.googledrive.com/host/0B61ekPEN_94sZ21mcnQtbVU2RHM/film_reel.png")));
mediaMetadata.putString(MediaMetadata.KEY_TITLE, "My MOVIE"+": "+videoTitle);
mediaInfo = new MediaInfo.Builder(ipdevice).setContentType(mimetype).setStreamType(MediaInfo.STREAM_TYPE_BUFFERED).setMetadata(mediaMetadata).build();
break;
case "photo" : mediaMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_PHOTO);
mediaMetadata.putString(MediaMetadata.KEY_TITLE, "My PHOTO"+": ");
mediaInfo = new MediaInfo.Builder(ipdevice).setContentType(mimetype).setStreamType(MediaInfo.STREAM_TYPE_BUFFERED).setMetadata(mediaMetadata).build();
break;
default:
}
try {
Cast.CastApi.setMessageReceivedCallbacks(mApiClient,mRemoteMediaPlayer.getNamespace(), mRemoteMediaPlayer);
} catch (IOException e) {
Log.d(TAG, "Exception while creating media channel", e);
}
try {
mRemoteMediaPlayer.load(mApiClient, mediaInfo, false,0).setResultCallback(new ResultCallback<RemoteMediaPlayer.MediaChannelResult>() {
#Override
public void onResult(MediaChannelResult result) {
if (result.getStatus().isSuccess()) {
Log.d(TAG, "Media loaded successfully");
}
}});
/*
* checks if the video is playing or if it is paused and according it will be played/paused in the receiver
*/
videoview.setPlayPauseListener(new CustomVideoView.PlayPauseListener() {
AudioManager amanager=(AudioManager)getSystemService(Context.AUDIO_SERVICE);
#Override
public void onPlay() {
playbackPaused=false; //videoView is playing
if(mSelectedDevice!=null && mApiClient != null && mRemoteMediaPlayer != null){
//volume is set to mute if media is casting in Chromecast
amanager.setStreamMute(AudioManager.STREAM_MUSIC, true);
sendMediaControl(playbackPaused,false);
}else{
amanager.setStreamVolume(AudioManager.STREAM_MUSIC, 3,1);
}
}
#Override
public void onPause(){
playbackPaused=true; //videoView is paused
if (mSelectedDevice != null && mApiClient != null && mRemoteMediaPlayer != null){
amanager.setStreamMute(AudioManager.STREAM_MUSIC, false);
sendMediaControl(playbackPaused,false);
}else{
amanager.setStreamVolume(AudioManager.STREAM_MUSIC, 3,1); }
}
/* Currently Seek function is not working for the media playback while casting
* (non-Javadoc)
* #see com.castoffline.castActivity.CustomVideoView.PlayPauseListener#onSeekChanged(int)
*/
#Override
public void onSeekChanged(int pos){
Log.d(String.valueOf(videoview.getCurrentPosition()),"seekinsie");
// seek(videoview.getCurrentPosition());
Log.d("mimetype ",mimetype);
Log.d("seek1",""+pos);
if (mSelectedDevice != null && mApiClient != null && mRemoteMediaPlayer != null){
videoview.pause();
final long position=videoview.getCurrentPosition();
Log.d("seek",""+position);
mRemoteMediaPlayer.seek(mApiClient,position,RemoteMediaPlayer.RESUME_STATE_UNCHANGED).setResultCallback(new ResultCallback<RemoteMediaPlayer.MediaChannelResult>(){
#Override
public void onResult(MediaChannelResult result) {
if (result.getStatus().isSuccess()) {
Log.d(String.valueOf("State Code "+result.getStatus().getStatusCode()),""+mRemoteMediaPlayer.getApproximateStreamPosition());
}
}
});
mRemoteMediaPlayer.setOnStatusUpdatedListener(new RemoteMediaPlayer.OnStatusUpdatedListener(){
#Override
public void onStatusUpdated() {
#SuppressWarnings("unused")
MediaStatus mediaStatus = mRemoteMediaPlayer.getMediaStatus();
Log.d("seek state update",""+mediaStatus);
}
});
}
}
});
} catch (IllegalStateException e) {
Log.d(TAG, "Problem occurred with media during loading", e);
} catch (Exception e) {
Log.d(TAG, "Problem opening media during loading", e);}
} else {
Log.e(TAG,"application could not launch");
teardown();
}
}
});
}
Remote player control code.
private void sendMediaControl(final boolean playbackPaused,final boolean change)
{
if (mApiClient != null && mRemoteMediaPlayer != null){
mRemoteMediaPlayer.requestStatus(mApiClient).setResultCallback( new ResultCallback<RemoteMediaPlayer.MediaChannelResult>() {
#Override
public void onResult(RemoteMediaPlayer.MediaChannelResult mediaChannelResult) {
if(playbackPaused ==true){
mRemoteMediaPlayer.pause(mApiClient);
}else{
mRemoteMediaPlayer.play(mApiClient);
}
}
});
}
}
There can be two things here:
I don't know if it is a limitation of nanohttpd or a configuration issue but what you are seeing is because the nanaohttpd (at least the way you have configured it) doesn't support seek. When you do a seek, your receiver will call into your http server (nanohttpd in this case) and passes a position and asks the web server to seek to that position and start streaming from there. If the web server doesn't support that, you will not be able to seek successfully. As a test, set up an apache server on your laptop, just for testing, and point to that instead of your embedded web server and see if that works or not.
There might be a mismatch between units of position; so if, say, your local player is using seconds and is reporting, say, 60 when it is a minute into the content and if you send that to the cast receiver, it will be interpreted as 60 milliseconds which is practically same as 0 seconds, so check on that too.
Related
Cast video using Chromecast in a queue is working fine. As per my requirement, it's need to play video constantly for hours on the screen. For that i get bunch of video urls from server for 5 to 10 videos. When 2 video are remain i get new bunch and i append in a queue. Videos are with the length around 40 to 50 seconds.
It continues play for about 45 to 60 min not more than that. It stops than.
I want it to play for hours...
Can any one Help me to come out from this issue. Any help will be useful for me.
Here is my code to play queue.
public void queuePlay(ArrayList<CastModel> data) {
ArrayList<MediaQueueItem> queueList = new ArrayList<>();
for (int i = 0; i < data.size(); i++) {
MediaMetadata mediaMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE);
mediaMetadata.putString(MediaMetadata.KEY_TITLE, data.get(i).vTitle);
mediaMetadata.putString(MediaMetadata.KEY_SUBTITLE, data.get(i).vName);
mediaMetadata.addImage(new WebImage(Uri.parse(data.get(i).vImage)));
JSONObject extraData = null;
try {
extraData = getJsonOfObject(data.get(i));
if (extraData == null)
extraData = new JSONObject();
} catch (Exception e) {
Log.i(TAG, "queuePlay: exception " + e.toString());
}
MediaInfo mediaInfo = new MediaInfo.Builder(data.get(i).vVideo)
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
.setContentType("videos/mp4")
.setMetadata(mediaMetadata)
.setCustomData(extraData)
.setStreamDuration(30 * 1000)
.build();
MediaQueueItem item = new MediaQueueItem.Builder(mediaInfo).build();
queueList.add(item);
}
MediaQueueItem[] queueArray = new MediaQueueItem[queueList.size()];
queueArray = queueList.toArray(queueArray);
remoteMediaClient = sessionManager.getCurrentCastSession().getRemoteMediaClient();
remoteMediaClient.queueLoad(queueArray, 0, REPEAT_MODE_REPEAT_OFF, null);
remoteMediaClient.addListener(new RemoteMediaClient.Listener() {
#Override
public void onStatusUpdated() {
try {
Thread.sleep(1000); // Hold for a while
} catch (InterruptedException e) {
e.printStackTrace();
}
MediaStatus mMediaStatus = remoteMediaClient.getMediaStatus();
if (mMediaStatus != null && mMediaStatus.getQueueItems() != null) {
if (queueItemPlayedPosition < mMediaStatus.getCurrentItemId()) {
Log.w(TAG, "onStatusUpdated: Delete video " + queueItemPlayedPosition);
updateCastList(false);
queueItemPlayedPosition++;
}
Log.e(TAG, "onStatusUpdated getCurrentItemId " + remoteMediaClient.getMediaStatus().getCurrentItemId() + " *** onStatusUpdated: getQueueItemCount *** " + mMediaStatus.getQueueItemCount());
}
}
#Override
public void onMetadataUpdated() {
}
#Override
public void onQueueStatusUpdated() {
}
#Override
public void onPreloadStatusUpdated() {
}
#Override
public void onSendingRemoteMediaRequest() {
}
});
}
Haven't played with Cast SDK a lot but found this Autoplay & Queueing APIs which might provide what you're looking for as it mentions ways to play videos continuously using autoplay.
I have just started exploring google-play-services-turnbased APIs. Till now I have been successful in creating a match. But from the documentation I haven't been able to figure out how to player's score after he completes his turn.
This is my onClickStartMatch method.
public void onStartMatchClicked() {
Intent intent =
Games.TurnBasedMultiplayer.getSelectOpponentsIntent(mHelper.getApiClient(), 1, 7, true);
startActivityForResult(intent, RC_SELECT_PLAYERS);
}
This is my onActivityResult method in my main activity class.
if (request == RC_SELECT_PLAYERS) {
if (response != RESULT_OK) {
// user canceled
return;
}
// Get the invitee list.
final ArrayList<String> invitees =
data.getStringArrayListExtra(Games.EXTRA_PLAYER_IDS);
// Get auto-match criteria.
Bundle autoMatchCriteria = null;
int minAutoMatchPlayers = data.getIntExtra(
Multiplayer.EXTRA_MIN_AUTOMATCH_PLAYERS, 0);
int maxAutoMatchPlayers = data.getIntExtra(
Multiplayer.EXTRA_MAX_AUTOMATCH_PLAYERS, 0);
if (minAutoMatchPlayers > 0) {
autoMatchCriteria = RoomConfig.createAutoMatchCriteria(
minAutoMatchPlayers, maxAutoMatchPlayers, 0);
} else {
autoMatchCriteria = null;
}
TurnBasedMatchConfig tbmc = TurnBasedMatchConfig.builder()
.addInvitedPlayers(invitees)
.setAutoMatchCriteria(autoMatchCriteria)
.build();
// Create and start the match.
Games.TurnBasedMultiplayer
.createMatch(mHelper.getApiClient(), tbmc)
.setResultCallback(new MatchInitiatedCallback());
}
This is my MatchInitiatedCallback class
public class MatchInitiatedCallback implements
ResultCallback<TurnBasedMultiplayer.InitiateMatchResult>,OnTurnBasedMatchUpdateReceivedListener {
#Override
public void onResult(TurnBasedMultiplayer.InitiateMatchResult result) {
// Check if the status code is not success.
Status status = result.getStatus();
if (status.isSuccess()) {
Log.d("turnbased","Turn Based Match Initiated successfully with result: "+status.getStatusMessage());
return;
}
TurnBasedMatch match = result.getMatch();
// If this player is not the first player in this match, continue.
if (match.getData() != null) {
showTurnUI(match);
return;
}
// Otherwise, this is the first player. Initialize the game state.
initGame(match);
// Let the player take the first turn
showTurnUI(match);
}
public void showTurnUI(TurnBasedMatch match){
if(match.getStatus() == TurnBasedMatch.MATCH_STATUS_ACTIVE){
if(match.getTurnStatus() == TurnBasedMatch.MATCH_TURN_STATUS_MY_TURN){
turnBasedMatchData = match.getData();
Games.TurnBasedMultiplayer.takeTurn(mHelper.getApiClient(),match.getMatchId(), "score:400".getBytes(Charset.forName("UTF-16")),null).setResultCallback(updateMatchResult());
}
}
}
public void initGame(TurnBasedMatch match){
Games.TurnBasedMultiplayer.takeTurn(mHelper.getApiClient(),match.getMatchId(),"score:605".getBytes(Charset.forName("UTF-16")),match.getParticipantId(Games.Players.getCurrentPlayerId(mHelper.getApiClient()))).setResultCallback(updateMatchResult());
}
public ResultCallback<TurnBasedMultiplayer.UpdateMatchResult> updateMatchResult(){
return null;
}
#Override
public void onTurnBasedMatchReceived(TurnBasedMatch turnBasedMatch) {
Log.d("turn-based","Player played his turn");
}
#Override
public void onTurnBasedMatchRemoved(String s) {
}
}
}
Also it would helpful if some can properly explain how to continue a game a game from start and when to submit score and how.
Figured it out. This is how you can do it.
public byte[] persist() {
JSONObject retVal = new JSONObject();
try {
retVal.put("turnCounter", 2);
retVal.put("score1",100);
retVal.put("score2",200);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String st = retVal.toString();
Log.d(TAG, "==== PERSISTING\n" + st);
return st.getBytes(Charset.forName("UTF-8"));
}
Games.TurnBasedMultiplayer.takeTurn(mHelper.getApiClient(),match.getMatchId(),persist(),null).setResultCallback(updateMatchResult());
I wrote a custom plugin to read blocks of data from an NfcA(i.e.non-ndef) tag. It seems to work fine , but only after the second scan. I am using Activity intent to derive the "NfcAdapter.EXTRA_TAG" to later use it for reading the values. I am also updating the Intents in onNewIntent(). OnNewIntent gets called after the second scan and after that I get result all the time.But in the first scan onNewIntent does not gets called, hence I end up using the Activity tag that does not have "NfcAdapter.EXTRA_TAG", hence I get null. Please see the my code below.
SE_NfcA.java(my native code for plugin)
#Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
String Result = "";
String TypeOfTalking = "";
if (action.contains("TalkToNFC"))
{
JSONObject arg_object = args.getJSONObject(0);
TypeOfTalking = arg_object.getString("type");
if(TypeOfTalking != "")
{
if (TypeOfTalking.contains("readBlock"))
{
if(TypeOfTalking.contains("#"))
{
try
{
String[] parts = TypeOfTalking.split("#");
int index = Integer.parseInt(parts[1]);
Result = Readblock(cordova.getActivity().getIntent(),(byte)index);
callbackContext.success(Result);
}
catch(Exception e)
{
callbackContext.error("Exception Reading "+ TypeOfTalking + "due to "+ e.toString());
return false;
}
}
}
else
{
return false;
}
}
else
{
return false;
}
}
else
{
return false;
}
return true;
}
#Override
public void onNewIntent(Intent intent) {
ShowAlert("onNewIntent called");
Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
super.onNewIntent(intent);
getActivity().setIntent(intent);
savedTag = tagFromIntent;
savedIntent = intent;
}
#Override
public void onPause(boolean multitasking) {
Log.d(TAG, "onPause " + getActivity().getIntent());
super.onPause(multitasking);
if (multitasking) {
// nfc can't run in background
stopNfc();
}
}
#Override
public void onResume(boolean multitasking) {
Log.d(TAG, "onResume " + getActivity().getIntent());
super.onResume(multitasking);
startNfc();
}
public String Readblock(Intent Intent,byte block) throws IOException{
byte[] response = new byte[]{};
if(Intent != null)
{
Tag myTag = Intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
if(savedTag != null)
myTag = savedTag;
if(myTag != null)
{
try{
Reader nTagReader = new Reader(myTag);
nTagReader.close();
nTagReader.connect();
nTagReader.SectorSelect(Sector.Sector0);
response = nTagReader.fast_read(block, block);
nTagReader.close();
return ConvertH(response);
}catch(Exception e){
ShowAlert(e.toString());
}
}
else
ShowAlert("myTag is null.");
}
return null;
}
private void createPendingIntent() {
if (pendingIntent == null) {
Activity activity = getActivity();
Intent intent = new Intent(activity, activity.getClass());
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP| Intent.FLAG_ACTIVITY_CLEAR_TOP);
pendingIntent = PendingIntent.getActivity(activity, 0, intent, 0);
}
}
private void startNfc() {
createPendingIntent(); // onResume can call startNfc before execute
getActivity().runOnUiThread(new Runnable() {
public void run() {
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(getActivity());
if (nfcAdapter != null && !getActivity().isFinishing()) {
try {
nfcAdapter.enableForegroundDispatch(getActivity(), getPendingIntent(), getIntentFilters(), getTechLists());
if (p2pMessage != null) {
nfcAdapter.setNdefPushMessage(p2pMessage, getActivity());
}
} catch (IllegalStateException e) {
// issue 110 - user exits app with home button while nfc is initializing
Log.w(TAG, "Illegal State Exception starting NFC. Assuming application is terminating.");
}
}
}
});
}
private void stopNfc() {
Log.d(TAG, "stopNfc");
getActivity().runOnUiThread(new Runnable() {
public void run() {
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(getActivity());
if (nfcAdapter != null) {
try {
nfcAdapter.disableForegroundDispatch(getActivity());
} catch (IllegalStateException e) {
// issue 125 - user exits app with back button while nfc
Log.w(TAG, "Illegal State Exception stopping NFC. Assuming application is terminating.");
}
}
}
});
}
private Activity getActivity() {
return this.cordova.getActivity();
}
private PendingIntent getPendingIntent() {
return pendingIntent;
}
private IntentFilter[] getIntentFilters() {
return intentFilters.toArray(new IntentFilter[intentFilters.size()]);
}
private String[][] getTechLists() {
//noinspection ToArrayCallWithZeroLengthArrayArgument
return techLists.toArray(new String[0][0]);
}
}
My index.js file
nfc.addTagDiscoveredListener(
function(nfcEvent){
console.log(nfcEvent.tag.id);
alert(nfcEvent.tag.id);
window.echo("readBlock#88");//call to plugin
},
function() {
alert("Listening for NFC tags.");
},
function() {
alert("NFC activation failed.");
}
);
SE_NfcA.js(plugin interface for interaction b/w index.js and SE_NfcA.java)
window.echo = function(natureOfTalk)
{
alert("Inside JS Interface, arg =" + natureOfTalk);
cordova.exec(function(result){alert("Result is : "+result);},
function(error){alert("Some Error happened : "+ error);},
"SE_NfcA","TalkToNFC",[{"type": natureOfTalk}]);
};
I guess I have messed up with the Intents/Activity Life-Cycle, please help. TIA!
I found a tweak/hack and made it to work.
Before making any call to read or write, I made one dummy Initialize call.
window.echo("Initialize");
window.echo("readBlock#88");//call to plugin to read.
And in the native code of the plugin, on receiving the "Initialize" token I made a startNFC() call.
else if(TypeOfTalking.equalsIgnoreCase("Initialize"))
{
startNfc();
}
I have been messing around with the following issue for about 2 months now.
I am building an application on a custom android board which will act as a wifi display (WFD). When I boot the board, I can easily connect from several different phones (LG Optimus G, LG Optimus G pro, Samsung S3 and S4). After connecting and watching the screen being duplicated on the TV screen attached to the custom board, I can then disconnect and if I reconnect within 2 minutes, I can connect again.
If I boot the board (or disconnect) and then wait 2 minutes, the device no longer sees the phones, and the phones sometimes sees the board, and sometimes not. If the phone sees the board, I can initiate a connect, but I cannot connect succesfully.
I have tried all kind of options, but none seem viable.
The board is running on AOSP 4.2.2
I have right now some complicated code that does restart the discoverPeers function every 40 seconds, as normally it stops after 30 seconds. Besides that I disable WFD and re-enable it, with a 4 second delay between it.
I also tried disabling and reenabling p2p and the channel, all with no result.
Below is my code, the receiver is in a separate class.
#Override
protected void onCreate(Bundle savedInstanceState)
{
Settings.System.putInt(getContentResolver(), Settings.System.WIFI_SLEEP_POLICY, Settings.System.WIFI_SLEEP_POLICY_NEVER);
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC,
audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC), 0);
setContentView(R.layout.wifi_direct_discovery);
connectPicture = findViewById(R.id.LinearLayout1);
Log.d(TAG, "onCreate");
isConnecting = false;
localWifiP2pWfdInfo = new WifiP2pWfdInfo();
localWifiP2pWfdInfo.setWfdEnabled(true);
localWifiP2pWfdInfo.setDeviceType(1);
localWifiP2pWfdInfo.setSessionAvailable(true);
localWifiP2pWfdInfo.setControlPort(7236);
localWifiP2pWfdInfo.setMaxThroughput(50);
final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "My Tag");
wl.acquire();
super.onCreate(savedInstanceState);
}
#Override
public void onPeersAvailable(WifiP2pDeviceList peers)
{
List<WifiP2pDevice> peersList = new ArrayList<WifiP2pDevice>();
final ArrayList<String> list = new ArrayList<String>();
final ListView listview = (ListView) findViewById(R.id.deviceListView);
peersList.clear();
peersList.addAll(peers.getDeviceList());
if (peersList.size() == 0)
{
Log.d(TAG, "No devices found");
list.clear();
if ((pd != null) && pd.isShowing() && (isConnecting == false))
{
pd.dismiss();
Log.d(TAG, "Closed connecting dialog, restarting P2P");
Toast.makeText(this, "Connection failed please try again", Toast.LENGTH_LONG).show();
restartP2p(false);
}
else if (isConnecting == false)
{
restartP2p(false);
}
listview.setAdapter(new ArrayAdapter<String>(this, R.layout.list_black_text, R.id.list_content, list));
return;
}
else
{
int i = 0;
boolean found = false;
for (i = 0; i < peersList.size(); i++)
{
Log.d(TAG, "Found device: " + peersList.get(i).toString());
list.add(peersList.get(i).deviceName);
if ((pd != null) && pd.isShowing())
{
if (peersList.get(i).deviceAddress.equalsIgnoreCase(client.deviceAddress))
{
found = true;
}
}
}
if (!found)
{
if ((pd != null) && pd.isShowing())
{
Log.d(TAG, "Failed to find current client: closed connecting dialog, restarting P2P");
Toast.makeText(this, "Disconnected please try again", Toast.LENGTH_LONG).show();
restartP2p(false);
}
else
{
Log.d(TAG, "Failed to find current client, but we weren't trying to connect");
}
}
}
listview.setAdapter(new ArrayAdapter<String>(this, R.layout.list_black_text, R.id.list_content, list));
}
#Override
public void onConnectionInfoAvailable(WifiP2pInfo p2pInfo)
{
if (p2pInfo.isGroupOwner)
{
stopP2PDispeerTimeoutThread();
Log.d(TAG, "Connected as group owner");
int i = p2pInfo.mWfdRtspPort;
Log.d(TAG, "------------------------- onConnectionInfoAvailable rtsp port = " + i);
// get the ip addres from the connected client. Mac address is in
// client
String sourceIP = null;
while (sourceIP == null)
{
sourceIP = getIPFromMac(client.deviceAddress);
millisleep(250);
if (sourceIP == null)
{
Log.e(TAG, "Failed to get client address!!!!! from " + client.deviceAddress);
}
}
if (i == 0)
{
// this is not a wfd source, so let's get into client mode for
// upgrade etc.
Log.e(TAG, "This device is not a WFD source, so switch to client mode, device = "
+ client.deviceAddress);
}
else
{
Log.d(TAG, "Start connect to source : " + sourceIP);
if ((pd != null) && pd.isShowing())
pd.dismiss();
// need to stop the connection timeout thread here..
stopConnectTimeoutThread();
Intent intent = new Intent(getBaseContext(), WFDPlayActivity.class);
intent.putExtra("SOURCE_IP", sourceIP);
intent.putExtra("RTSPPORT", i);
startActivityForResult(intent, 210);
}
}
else
{
Log.e(TAG, "Connected as peer, this is very very wrong!!!!, restartP2P");
restartP2p(false);
startP2PDispeerTimeoutThread(34);
}
}
#Override
public void onConnectionRequested(WifiP2pDevice arg0, WifiP2pConfig arg1)
{
Log.d(TAG, "------------------------------------- onConnectionRequested");
stopP2PDispeerTimeoutThread();
isConnecting = true;
client = arg0;
if ((pd != null) && (pd.isShowing()))
{
pd.dismiss();
}
if (client != null)
{
createConnectionProgressDialog(client.deviceName);
}
}
public void onResume()
{
if (first_time == false)
{
Log.d(TAG, "onResume");
intentFilter.addAction("android.net.wifi.p2p.STATE_CHANGED");
intentFilter.addAction("android.net.wifi.p2p.PEERS_CHANGED");
intentFilter.addAction("android.net.wifi.p2p.CONNECTION_STATE_CHANGE");
intentFilter.addAction("android.net.wifi.p2p.THIS_DEVICE_CHANGED");
registerReceiver(receiver, intentFilter);
if (!mP2PDispeerThread.isRunning)
startP2PDispeerTimeoutThread(34);
manager.setDialogListener(channel, this);
manager.discoverPeers(channel, new WifiP2pManager.ActionListener()
{
#Override
public void onSuccess()
{
Log.d(TAG, "discoverPeers success");
}
#Override
public void onFailure(int reasonCode)
{
Log.d(TAG, "discoverPeers failed");
}
});
}
else
{
Log.d(TAG, "onResume, first time");
restartP2p(first_time);
first_time = false;
}
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
super.onResume();
}
public void restartP2p(boolean first)
{
if (first)
{
mWifiManager = ((WifiManager) getSystemService("wifi"));
mWifiManager.setWifiEnabled(true);
sleep(4); // was 4
manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
channel = manager.initialize(this, getMainLooper(), null);
manager.enableP2p(channel);
sleep(3); // was 3
mDisplayManager = ((DisplayManager) getSystemService("display"));
intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
mlock = mWifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF , "LockTag");
mlock.acquire();
instance = this;
receiver = new WiFiDirectBroadcastReceiver(manager, channel, this);
registerReceiver(receiver, intentFilter);
manager.setWFDInfo(channel, localWifiP2pWfdInfo, new WifiP2pManager.ActionListener()
{
public void onFailure(int paramAnonymousInt)
{
Log.d(TAG, "Failed to set WFD info with reason " + paramAnonymousInt + ".");
}
public void onSuccess()
{
Log.d(TAG, "updateWfdEnableState");
}
});
sleep(1);
manager.setDialogListener(channel, this);
manager.discoverPeers(channel, new WifiP2pManager.ActionListener()
{
#Override
public void onSuccess()
{
Log.d(TAG, "discoverPeers success");
}
#Override
public void onFailure(int reasonCode)
{
Log.d(TAG, "discoverPeers failed");
}
});
}
else
{
manager.stopPeerDiscovery(channel, new WifiP2pManager.ActionListener()
{
#Override
public void onSuccess()
{
Log.d(TAG, "stopPeerDiscovery success");
}
#Override
public void onFailure(int reasonCode)
{
Log.d(TAG, "stopPeerDiscovery failed");
}
});
localWifiP2pWfdInfo.setWfdEnabled(false);
manager.setWFDInfo(channel, localWifiP2pWfdInfo, new WifiP2pManager.ActionListener()
{
public void onFailure(int paramAnonymousInt)
{
Log.d(TAG, "Failed to set WFD info with reason " + paramAnonymousInt + ".");
}
public void onSuccess()
{
Log.d(TAG, "updateWfdEnableState");
}
});
sleep(4);
localWifiP2pWfdInfo.setWfdEnabled(true);
manager.setWFDInfo(channel, localWifiP2pWfdInfo, new WifiP2pManager.ActionListener()
{
public void onFailure(int paramAnonymousInt)
{
Log.d(TAG, "Failed to set WFD info with reason " + paramAnonymousInt + ".");
}
public void onSuccess()
{
Log.d(TAG, "updateWfdEnableState");
}
});
manager.discoverPeers(channel, new WifiP2pManager.ActionListener()
{
#Override
public void onSuccess()
{
Log.d(TAG, "discoverPeers success");
}
#Override
public void onFailure(int reasonCode)
{
Log.d(TAG, "discoverPeers failed");
}
});
}
if (first)
startP2PDispeerTimeoutThread(40); // only start the thread 1 time...
}
In the logging initially I see that the device and the phone connect successfully.
After disconnect, I see the devices being lost in the log, and after that, when I try to connect, I see the message:
I/wpa_supplicant(1839): [CTRL_IFACE]p2p0: P2P_CONNECT da:57:ef:cb:8e:be pbc go_intent=0
After this everything stops, the application is still running, I could see that from a log line that runs every second in the thread that stops and restarts the discovery every 40 seconds.
If anyone has any idea left why this behavior is happening, let me know. The only way to recover right now is to reboot the board (but that is not an option).
Thanks for your replies,
Arvy
I am new in SIP call using RTP, now I am trying to send and receive
voice streams using RTP for sip call. I am done with connecting
two emulators and able to send INVITE and INVITE-ACK using jain sip.
After I got an Ack I want to start RTP for media streaming, I use the RtpPacket
function to send and receive
I use RtpFunction to send media with all RTP header like this:
byte Version;
boolean Padding;
boolean Extension;
byte CC;
boolean Marker;
byte PayloadType;
short SequenceNumber;
int TimeStamp;
Please give some ideas and actual links where I can find an answer.
This can be achieved in a simpler manner
AudioManager audio = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
audio.setMode(AudioManager.MODE_IN_COMMUNICATION);
audioGroup = new AudioGroup();
audioGroup.setMode(AudioGroup.MODE_ECHO_SUPPRESSION);
audioStream = new AudioStream(InetAddress.getByAddress(getLocalIPAddress()));
audioStream.setCodec(AudioCodec.PCMU);
audioStream.setMode(RtpStream.MODE_NORMAL);
audioStream.associate(InetAddress.getByName(SipStackAndroid.getRemoteIp()), REMOTE_PORT);
audioStream.join(audioGroup);
We send and receive RTP data using RTPpacket.
import javax.media.rtp.*;
import javax.media.rtp.rtcp.*;
import javax.media.rtp.event.*;
import javax.media.*;
import javax.media.protocol.*;
import java.net.InetAddress;
import javax.media.format.AudioFormat;
import com.sun.media.ui.*;
import java.util.Vector;
public class RTPSourceStream < RTPPlayerWindow > implements ReceiveStreamListener,
ControllerListener {
#SuppressWarnings("rawtypes")
Vector playerlist = new Vector();
#SuppressWarnings("deprecation")
SessionManager mgr = null;
boolean terminatedbyClose = false;
#SuppressWarnings("deprecation")
public SessionManager createManager(String address,
String sport,
String sttl,
boolean listener,
boolean sendlistener) {
return createManager(address,
new Integer(sport).intValue(),
new Integer(sttl).intValue(),
listener,
sendlistener);
}
#SuppressWarnings("deprecation")
public SessionManager createManager(String address,
int port,
int ttl,
boolean listener,
boolean sendlistener) {
mgr = (SessionManager) new com.sun.media.rtp.RTPSessionMgr();
if (mgr == null) return null;
mgr.addFormat(new AudioFormat(AudioFormat.DVI_RTP, 44100, 4, 1), 18);
if (listener) mgr.addReceiveStreamListener(this);
// if (sendlistener) new RTPSendStreamWindow(mgr);
// ask RTPSM to generate the local participants CNAME
String cname = mgr.generateCNAME();
String username = null;
try {
username = System.getProperty("user.name");
} catch (SecurityException e) {
username = "jmf-user";
}
// create our local Session Address
SessionAddress localaddr = new SessionAddress();
try {
InetAddress destaddr = InetAddress.getByName(address);
SessionAddress sessaddr = new SessionAddress(destaddr,
port,
destaddr,
port + 1);
SourceDescription[] userdesclist = new SourceDescription[] {
new SourceDescription(SourceDescription
.SOURCE_DESC_EMAIL,
"jmf-user#sun.com",
1,
false),
new SourceDescription(SourceDescription
.SOURCE_DESC_CNAME,
cname,
1,
false),
new
SourceDescription(SourceDescription.SOURCE_DESC_TOOL, "JMF RTP Player v2.0",
1,
false)
};
mgr.initSession(localaddr,
userdesclist,
0.05,
0.25);
mgr.startSession(sessaddr, ttl, null);
} catch (Exception e) {
System.err.println(e.getMessage());
return null;
}
return mgr;
}
public void update(ReceiveStreamEvent event) {
Player newplayer = null;
RTPPacket playerWindow = null;
// find the sourceRTPSM for this event
SessionManager source = (SessionManager) event.getSource();
// create a new player if a new recvstream is detected
if (event instanceof NewReceiveStreamEvent) {
String cname = "Java Media Player";
ReceiveStream stream = null;
try {
// get a handle over the ReceiveStream
stream = ((NewReceiveStreamEvent) event)
.getReceiveStream();
Participant part = stream.getParticipant();
if (part != null) cname = part.getCNAME();
// get a handle over the ReceiveStream datasource
DataSource dsource = stream.getDataSource();
// create a player by passing datasource to the
// Media Manager
newplayer = Manager.createPlayer(dsource);
System.out.println("created player " + newplayer);
} catch (Exception e) {
System.err.println("NewReceiveStreamEvent exception " +
e.getMessage());
return;
}
if (newplayer == null) return;
playerlist.addElement(newplayer);
newplayer.addControllerListener(this);
// send this player to player GUI
playerWindow = new RTPPacket(newplayer, cname);
}
}
public void controllerUpdate(ControllerEvent evt) {
// get a handle over controller, remove it from the player
// list.
// if player list is empty, close the sesssion manager.
if ((evt instanceof ControllerClosedEvent) ||
(evt instanceof ControllerErrorEvent) ||
(evt instanceof DeallocateEvent)) {
Player p = (Player) evt.getSourceController();
if (!terminatedbyClose) {
if (playerlist.contains(p))
playerlist.removeElement(p);
if ((playerlist.size() == 0) && (mgr != null))
mgr.closeSession("All players are closed");
}
}
}
public void closeManager() {
terminatedbyClose = true;
// first close all the players
for (int i = 0; i < playerlist.size(); i++) {
((Player) playerlist.elementAt(i)).close();
}
if (mgr != null) {
mgr.closeSession("RTP Session Terminated");
mgr = null;
}
}
class RTPPacket extends RTPSourceStream {
public RTPPacket(Player newplayer, String cname) {
// TODO Auto-generated constructor stub
}
}
}