1
0
mirror of git://f0xx.org/android_cast synced 2026-07-29 07:20:00 +03:00
This commit is contained in:
Anton Afanasyeu
2026-05-15 17:50:46 +02:00
parent 65af9331be
commit 4de71d5400
4 changed files with 44 additions and 31 deletions

View File

@@ -143,7 +143,6 @@ public class ReceiverCastService extends Service {
private void restartListening(String pin) { private void restartListening(String pin) {
stopSessionOnly(); stopSessionOnly();
closePlaybackUi();
resetStreamState(); resetStreamState();
phase = Phase.LISTENING; phase = Phase.LISTENING;
acquireWakeLock(); acquireWakeLock();
@@ -233,15 +232,16 @@ public class ReceiverCastService extends Service {
}); });
session.start(); session.start();
updateStatus(getString(R.string.receiver_ready, pin, settings.getTransport().toUpperCase())); updateStatus(getString(R.string.receiver_ready, pin, settings.getTransport().toUpperCase()));
openPlaybackAwaiting(R.string.playback_listening);
Log.i(TAG, "Listening PIN=" + pin + " audio=" + allowIncomingAudio); Log.i(TAG, "Listening PIN=" + pin + " audio=" + allowIncomingAudio);
} }
private void onSenderConnected(String senderName) { private void onSenderConnected(String senderName) {
phase = Phase.CONNECTED; phase = Phase.CONNECTED;
audioAccepted = null; audioAccepted = null;
playbackLaunched = false;
updateStatus(getString(R.string.casting_from, senderName)); updateStatus(getString(R.string.casting_from, senderName));
broadcastAuthenticated(senderName); broadcastAuthenticated(senderName);
openPlaybackAwaiting(R.string.playback_awaiting_stream);
Log.i(TAG, "Sender connected: " + senderName); Log.i(TAG, "Sender connected: " + senderName);
} }
@@ -250,15 +250,16 @@ public class ReceiverCastService extends Service {
audioAccepted = null; audioAccepted = null;
hasPendingConfig = false; hasPendingConfig = false;
awaitingKeyframe = true; awaitingKeyframe = true;
resetDecoderState();
detachSurfaceOnly(); detachSurfaceOnly();
broadcastDisconnected(); broadcastDisconnected();
openPlaybackAwaiting(R.string.playback_stream_lost);
updateStatus(getString(R.string.waiting_sender)); updateStatus(getString(R.string.waiting_sender));
Log.i(TAG, "Sender disconnected"); Log.i(TAG, "Sender disconnected");
} }
private void resetStreamState() { private void resetStreamState() {
hasPendingConfig = false; hasPendingConfig = false;
playbackLaunched = false;
awaitingKeyframe = true; awaitingKeyframe = true;
pendingWidth = 0; pendingWidth = 0;
pendingHeight = 0; pendingHeight = 0;
@@ -328,26 +329,28 @@ public class ReceiverCastService extends Service {
hasPendingConfig = true; hasPendingConfig = true;
decoderActive = false; decoderActive = false;
mainHandler.postDelayed(() -> awaitingKeyframe = false, 2000); mainHandler.postDelayed(() -> awaitingKeyframe = false, 2000);
if (!playbackLaunched) {
playbackLaunched = true;
launchPlaybackActivity(pendingWidth, pendingHeight);
} else {
notifyPlaybackDimensions(pendingWidth, pendingHeight); notifyPlaybackDimensions(pendingWidth, pendingHeight);
}
tryConfigureDecoder(); tryConfigureDecoder();
reconfiguring = false; reconfiguring = false;
Log.i(TAG, "Stream config " + pendingWidth + "x" + pendingHeight); Log.i(TAG, "Stream config " + pendingWidth + "x" + pendingHeight);
} }
private void launchPlaybackActivity(int width, int height) { /** Opens or refreshes fullscreen UI with robot overlay (listening / waiting for stream). */
private void openPlaybackAwaiting(int messageResId) {
playbackLaunched = true;
Intent intent = new Intent(this, ReceiverPlaybackActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra(ReceiverPlaybackActivity.EXTRA_SHOW_AWAITING, true);
intent.putExtra(ReceiverPlaybackActivity.EXTRA_AWAITING_MESSAGE, messageResId);
startActivity(intent);
}
private void notifyPlaybackDimensions(int width, int height) {
Intent intent = new Intent(this, ReceiverPlaybackActivity.class); Intent intent = new Intent(this, ReceiverPlaybackActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra(ReceiverPlaybackActivity.EXTRA_WIDTH, width); intent.putExtra(ReceiverPlaybackActivity.EXTRA_WIDTH, width);
intent.putExtra(ReceiverPlaybackActivity.EXTRA_HEIGHT, height); intent.putExtra(ReceiverPlaybackActivity.EXTRA_HEIGHT, height);
startActivity(intent); startActivity(intent);
}
private void notifyPlaybackDimensions(int width, int height) {
broadcastStreamStarted(width, height); broadcastStreamStarted(width, height);
} }
@@ -510,6 +513,7 @@ public class ReceiverCastService extends Service {
private void releaseAll() { private void releaseAll() {
phase = Phase.IDLE; phase = Phase.IDLE;
resetStreamState(); resetStreamState();
playbackLaunched = false;
audioAccepted = null; audioAccepted = null;
stopSessionOnly(); stopSessionOnly();
closePlaybackUi(); closePlaybackUi();

View File

@@ -23,11 +23,16 @@ import com.foxx.androidcast.ICastStatusCallback;
import com.foxx.androidcast.R; import com.foxx.androidcast.R;
import com.foxx.androidcast.ui.AspectRatioFrameLayout; import com.foxx.androidcast.ui.AspectRatioFrameLayout;
/** Fullscreen video playback — robot overlay while waiting or after stream loss. */ /**
* Fullscreen display: dancing-robot overlay while listening / waiting;
* video surface shown only after the first decoded frame.
*/
public class ReceiverPlaybackActivity extends AppCompatActivity implements SurfaceHolder.Callback { public class ReceiverPlaybackActivity extends AppCompatActivity implements SurfaceHolder.Callback {
public static final String EXTRA_WIDTH = "video_width"; public static final String EXTRA_WIDTH = "video_width";
public static final String EXTRA_HEIGHT = "video_height"; public static final String EXTRA_HEIGHT = "video_height";
public static final String EXTRA_FINISH = "finish_playback"; public static final String EXTRA_FINISH = "finish_playback";
public static final String EXTRA_SHOW_AWAITING = "show_awaiting";
public static final String EXTRA_AWAITING_MESSAGE = "awaiting_message";
private AspectRatioFrameLayout aspectContainer; private AspectRatioFrameLayout aspectContainer;
private SurfaceView surfaceView; private SurfaceView surfaceView;
@@ -46,13 +51,7 @@ public class ReceiverPlaybackActivity extends AppCompatActivity implements Surfa
private final ICastStatusCallback.Stub statusCallback = new ICastStatusCallback.Stub() { private final ICastStatusCallback.Stub statusCallback = new ICastStatusCallback.Stub() {
@Override @Override
public void onStatus(String status) { public void onStatus(String status) {}
runOnUiThread(() -> {
if (status != null && status.toLowerCase().contains("waiting")) {
showAwaitingOverlay(R.string.playback_awaiting_stream);
}
});
}
@Override @Override
public void onAuthenticated(String senderName) { public void onAuthenticated(String senderName) {
@@ -85,10 +84,6 @@ public class ReceiverPlaybackActivity extends AppCompatActivity implements Surfa
bound = true; bound = true;
try { try {
receiverService.registerCallback(statusCallback); receiverService.registerCallback(statusCallback);
String status = receiverService.getStatus();
if (status != null && status.toLowerCase().contains("waiting")) {
showAwaitingOverlay(R.string.playback_awaiting_stream);
}
} catch (RemoteException ignored) { } catch (RemoteException ignored) {
} }
attachSurfaceIfReady(); attachSurfaceIfReady();
@@ -119,9 +114,14 @@ public class ReceiverPlaybackActivity extends AppCompatActivity implements Surfa
awaitingMessage = findViewById(R.id.text_awaiting_message); awaitingMessage = findViewById(R.id.text_awaiting_message);
surfaceHolder = surfaceView.getHolder(); surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this); surfaceHolder.addCallback(this);
surfaceView.setZOrderMediaOverlay(false);
robotDance = AnimationUtils.loadAnimation(this, R.anim.robot_dance); robotDance = AnimationUtils.loadAnimation(this, R.anim.robot_dance);
applyAspectRatio(); applyAspectRatio();
showAwaitingOverlay(R.string.playback_awaiting_stream);
if (getIntent().getBooleanExtra(EXTRA_SHOW_AWAITING, true)) {
int msg = getIntent().getIntExtra(EXTRA_AWAITING_MESSAGE, R.string.playback_listening);
showAwaitingOverlay(msg);
}
} }
@Override @Override
@@ -133,8 +133,9 @@ public class ReceiverPlaybackActivity extends AppCompatActivity implements Surfa
} }
readSizeFromIntent(intent); readSizeFromIntent(intent);
updateVideoSize(videoWidth, videoHeight); updateVideoSize(videoWidth, videoHeight);
if (!streamRendering) { if (intent.getBooleanExtra(EXTRA_SHOW_AWAITING, false)) {
showAwaitingOverlay(R.string.playback_awaiting_stream); int msg = intent.getIntExtra(EXTRA_AWAITING_MESSAGE, R.string.playback_listening);
showAwaitingOverlay(msg);
} }
} }
@@ -198,7 +199,11 @@ public class ReceiverPlaybackActivity extends AppCompatActivity implements Surfa
if (awaitingOverlay == null) { if (awaitingOverlay == null) {
return; return;
} }
if (surfaceView != null) {
surfaceView.setVisibility(View.INVISIBLE);
}
awaitingOverlay.setVisibility(View.VISIBLE); awaitingOverlay.setVisibility(View.VISIBLE);
awaitingOverlay.bringToFront();
if (awaitingMessage != null) { if (awaitingMessage != null) {
awaitingMessage.setText(messageResId); awaitingMessage.setText(messageResId);
} }
@@ -206,10 +211,12 @@ public class ReceiverPlaybackActivity extends AppCompatActivity implements Surfa
} }
private void hideAwaitingOverlay() { private void hideAwaitingOverlay() {
if (awaitingOverlay == null) { if (awaitingOverlay != null) {
return;
}
awaitingOverlay.setVisibility(View.GONE); awaitingOverlay.setVisibility(View.GONE);
}
if (surfaceView != null) {
surfaceView.setVisibility(View.VISIBLE);
}
stopRobotAnimation(); stopRobotAnimation();
} }

View File

@@ -5,6 +5,7 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="#CC000000" android:background="#CC000000"
android:clickable="true" android:clickable="true"
android:elevation="16dp"
android:focusable="true"> android:focusable="true">
<LinearLayout <LinearLayout

View File

@@ -42,6 +42,7 @@
<string name="label_receiver_audio">Play incoming cast audio on this device</string> <string name="label_receiver_audio">Play incoming cast audio on this device</string>
<string name="start_receiver">Start listening (keeps running in background)</string> <string name="start_receiver">Start listening (keeps running in background)</string>
<string name="playback_buffering">Connected — waiting for video…</string> <string name="playback_buffering">Connected — waiting for video…</string>
<string name="playback_listening">Listening for cast — awaiting sender…</string>
<string name="playback_awaiting_stream">Awaiting for stream to come…</string> <string name="playback_awaiting_stream">Awaiting for stream to come…</string>
<string name="playback_stream_lost">Stream lost — awaiting for stream to come…</string> <string name="playback_stream_lost">Stream lost — awaiting for stream to come…</string>
<string name="receiver_starting">Starting receiver service…</string> <string name="receiver_starting">Starting receiver service…</string>