Skip to content

Commit 0df8303

Browse files
authored
Feature: Intent-based Automation for PowerPlay Sample (#2341)
* Add intent-based automation support * Fix UI inconsistencies with the automation path * Remove toggle based intents. * Fix Merge conflict
1 parent af3a9ad commit 0df8303

9 files changed

Lines changed: 761 additions & 29 deletions

File tree

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
# PowerPlay Automation Guide
2+
3+
This guide explains how to control the PowerPlay audio player via ADB commands for automated testing of power-efficient audio features (PCM Offload).
4+
5+
## Quick Start
6+
7+
```bash
8+
# Build and install
9+
cd samples/powerplay
10+
../../gradlew installDebug
11+
12+
# Play with PCM Offload enabled
13+
adb shell am start -n com.google.oboe.samples.powerplay/.MainActivity \
14+
--es command play \
15+
--es perf_mode offload
16+
17+
# Monitor status
18+
adb logcat -s PowerPlay:V
19+
```
20+
21+
## Supported ADB Parameters
22+
23+
| Parameter | Type | Description | Example |
24+
| -------------------- | ------- | ---------------------------------------------------------- | ------------------------------ |
25+
| `command` | string | Action: `play`, `pause`, `stop` | `--es command play` |
26+
| `perf_mode` | string | Performance mode: `none`, `lowlat`, `powersave`, `offload` | `--es perf_mode offload` |
27+
| `song_index` | int | Track index (0-2) | `--ei song_index 1` |
28+
| `volume` | int | Volume percentage (0-100) | `--ei volume 50` |
29+
| `background` | boolean | Move app to background after starting | `--ez background true` |
30+
| `duration_ms` | int | Auto-stop after N milliseconds | `--ei duration_ms 10000` |
31+
| `use_mmap` | boolean | Enable/disable MMAP audio path | `--ez use_mmap false` |
32+
| `buffer_frames` | int | Buffer size in frames (offload only) | `--ei buffer_frames 4096` |
33+
34+
## Common Test Scenarios
35+
36+
### Test PCM Offload Mode
37+
```bash
38+
adb shell am start -n com.google.oboe.samples.powerplay/.MainActivity \
39+
--es command play \
40+
--es perf_mode offload
41+
```
42+
43+
### Background Playback Test
44+
```bash
45+
adb shell am start -n com.google.oboe.samples.powerplay/.MainActivity \
46+
--es command play \
47+
--es perf_mode offload \
48+
--ez background true
49+
```
50+
51+
### Timed Playback (10 seconds)
52+
```bash
53+
adb shell am start -n com.google.oboe.samples.powerplay/.MainActivity \
54+
--es command play \
55+
--es perf_mode offload \
56+
--ei duration_ms 10000
57+
```
58+
59+
### Compare Performance Modes
60+
```bash
61+
# Low Latency
62+
adb shell am start -n com.google.oboe.samples.powerplay/.MainActivity \
63+
--es command play --es perf_mode lowlat
64+
65+
# Power Saving (non-offload)
66+
adb shell am start -n com.google.oboe.samples.powerplay/.MainActivity \
67+
--es command play --es perf_mode powersave
68+
69+
# PCM Offload
70+
adb shell am start -n com.google.oboe.samples.powerplay/.MainActivity \
71+
--es command play --es perf_mode offload
72+
```
73+
74+
### Stop Playback
75+
```bash
76+
adb shell am start -n com.google.oboe.samples.powerplay/.MainActivity \
77+
--es command stop
78+
```
79+
80+
## Machine-Readable Status Logs
81+
82+
The app outputs status to logcat with the `PowerPlay` tag in a parseable format:
83+
84+
```
85+
POWERPLAY_STATUS: PLAYING | SONG=0 | OFFLOAD=true | MMAP=true
86+
POWERPLAY_STATUS: PAUSED
87+
POWERPLAY_STATUS: STOPPED | REASON=AUTO_STOP
88+
```
89+
90+
### Status Values
91+
| Status | Meaning |
92+
| ----------------- | ------------------------------------- |
93+
| `PLAYING` | Audio playback is active |
94+
| `PAUSED` | Audio playback is paused |
95+
| `STOPPED` | Audio playback has stopped |
96+
| `ERROR` | An error occurred |
97+
| `OFFLOAD_REVOKED` | PCM Offload was revoked by the system |
98+
99+
### Log Monitoring
100+
```bash
101+
# Real-time monitoring
102+
adb logcat -s PowerPlay:V
103+
104+
# Filter for status only
105+
adb logcat -s PowerPlay:V | grep "POWERPLAY_STATUS"
106+
107+
# Save to file
108+
adb logcat -s PowerPlay:V > powerplay_test.log
109+
```
110+
111+
## Using the Test Action
112+
113+
For automation scripts, you can also use the dedicated test action:
114+
115+
```bash
116+
adb shell am start -a com.google.oboe.samples.powerplay.TEST \
117+
--es command play \
118+
--es perf_mode offload
119+
```
120+
121+
## Battery Testing
122+
123+
To measure power consumption with offload vs non-offload:
124+
125+
```bash
126+
# Reset battery stats
127+
adb shell dumpsys batterystats --reset
128+
129+
# Run offload test for 5 minutes
130+
adb shell am start -n com.google.oboe.samples.powerplay/.MainActivity \
131+
--es command play \
132+
--es perf_mode offload \
133+
--ez background true \
134+
--ei duration_ms 300000
135+
136+
# Wait for test to complete, then capture stats
137+
adb shell dumpsys batterystats > battery_offload.txt
138+
```
139+
140+
## Troubleshooting
141+
142+
### Offload Not Activating
143+
- Ensure device supports PCM Offload: check `AudioManager.isOffloadedPlaybackSupported()`
144+
- Some devices only support offload with specific sample rates (usually 48kHz)
145+
- Display must be off for some implementations
146+
147+
### App Doesn't Respond to Commands
148+
- Make sure the app is installed: `adb shell pm list packages | grep powerplay`
149+
- Check if activity is exported: `adb shell dumpsys package com.google.oboe.samples.powerplay`
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
#!/bin/bash
2+
# PowerPlay Automation Test Script
3+
# Demonstrates a full test cycle: Open -> Play Offload -> Wait -> Close
4+
5+
set -e
6+
7+
PACKAGE="com.google.oboe.samples.powerplay"
8+
ACTIVITY="${PACKAGE}/.MainActivity"
9+
LOG_TAG="PowerPlay"
10+
TEST_DURATION_MS=10000 # 10 seconds
11+
12+
echo "=== PowerPlay Automation Test ==="
13+
echo ""
14+
15+
# Check device connection
16+
if ! adb devices | grep -q "device$"; then
17+
echo "ERROR: No Android device connected"
18+
exit 1
19+
fi
20+
21+
echo "[1/6] Checking if PowerPlay is installed..."
22+
if ! adb shell pm list packages | grep -q "$PACKAGE"; then
23+
echo "ERROR: PowerPlay is not installed. Please run:"
24+
echo " cd samples/powerplay && ../../gradlew installDebug"
25+
exit 1
26+
fi
27+
echo " ✓ PowerPlay is installed"
28+
29+
echo ""
30+
echo "[2/6] Force-stopping any existing instance..."
31+
adb shell am force-stop "$PACKAGE"
32+
sleep 1
33+
echo " ✓ App stopped"
34+
35+
echo ""
36+
echo "[3/6] Starting playback with PCM Offload mode..."
37+
adb shell am start -n "$ACTIVITY" \
38+
--es command play \
39+
--es perf_mode offload \
40+
--ei duration_ms "$TEST_DURATION_MS" \
41+
--ei volume 75
42+
43+
echo " ✓ Play command sent"
44+
45+
echo ""
46+
echo "[4/6] Monitoring status (waiting for ${TEST_DURATION_MS}ms)..."
47+
echo "---"
48+
49+
# Capture and display logs for the test duration
50+
timeout $((TEST_DURATION_MS / 1000 + 2)) adb logcat -s "$LOG_TAG:V" 2>/dev/null | while read -r line; do
51+
if echo "$line" | grep -q "POWERPLAY_STATUS"; then
52+
echo " LOG: $line"
53+
fi
54+
done || true
55+
56+
echo "---"
57+
echo " ✓ Test duration completed"
58+
59+
echo ""
60+
echo "[5/6] Verifying playback stopped..."
61+
FINAL_STATUS=$(adb logcat -d -s "$LOG_TAG:V" | grep "POWERPLAY_STATUS" | tail -1)
62+
if echo "$FINAL_STATUS" | grep -q "STOPPED"; then
63+
echo " ✓ Playback stopped correctly"
64+
else
65+
echo " ⚠ Last status: $FINAL_STATUS"
66+
fi
67+
68+
echo ""
69+
echo "[6/6] Checking offload status from logs..."
70+
if adb logcat -d -s "$LOG_TAG:V" | grep -q "OFFLOAD=true"; then
71+
echo " ✓ PCM Offload was active during playback"
72+
else
73+
echo " ⚠ PCM Offload may not have been active (device might not support it)"
74+
fi
75+
76+
echo ""
77+
echo "=== Test Complete ==="
78+
echo ""
79+
echo "Full logs saved to: powerplay_test.log"
80+
adb logcat -d -s "$LOG_TAG:V" > powerplay_test.log
81+
82+
echo ""
83+
echo "To run additional tests:"
84+
echo " # Background playback"
85+
echo " adb shell am start -n $ACTIVITY --es command play --es perf_mode offload --ez background true"

samples/powerplay/src/main/AndroidManifest.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,19 @@
1515
<activity
1616
android:name=".MainActivity"
1717
android:exported="true"
18+
android:launchMode="singleTop"
1819
android:theme="@style/Theme.Samples">
1920
<intent-filter>
2021
<action android:name="android.intent.action.MAIN" />
2122

2223
<category android:name="android.intent.category.LAUNCHER" />
2324
</intent-filter>
25+
26+
<!-- Intent filter for automation testing via ADB -->
27+
<intent-filter>
28+
<action android:name="com.google.oboe.samples.powerplay.TEST" />
29+
<category android:name="android.intent.category.DEFAULT" />
30+
</intent-filter>
2431
</activity>
2532

2633

samples/powerplay/src/main/cpp/PowerPlayJNI.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,47 @@ Java_com_google_oboe_samples_powerplay_engine_PowerPlayAudioPlayer_getBufferCapa
287287
return player.getBufferCapacityInFrames();
288288
}
289289

290+
/**
291+
* Native (JNI) implementation of PowerPlayAudioPlayer.setVolumeNative()
292+
*/
293+
JNIEXPORT void JNICALL
294+
Java_com_google_oboe_samples_powerplay_engine_PowerPlayAudioPlayer_setVolumeNative(
295+
JNIEnv *env,
296+
jobject,
297+
jfloat volume) {
298+
int32_t currentIndex = player.getCurrentlyPlayingIndex();
299+
if (currentIndex >= 0) {
300+
player.setGain(currentIndex, volume);
301+
return;
302+
}
303+
304+
// Set gain for all tracks if nothing is playing.
305+
for (int i = 0; i < 3; ++i) {
306+
player.setGain(i, volume);
307+
}
308+
}
309+
310+
/**
311+
* Native (JNI) implementation of PowerPlayAudioPlayer.isOffloadedNative()
312+
*/
313+
JNIEXPORT jboolean JNICALL
314+
Java_com_google_oboe_samples_powerplay_engine_PowerPlayAudioPlayer_isOffloadedNative(
315+
JNIEnv *env,
316+
jobject) {
317+
return player.isOffloaded();
318+
}
319+
320+
/**
321+
* Native (JNI) implementation of PowerPlayAudioPlayer.getCurrentlyPlayingIndexNative()
322+
*/
323+
JNIEXPORT jint JNICALL
324+
Java_com_google_oboe_samples_powerplay_engine_PowerPlayAudioPlayer_getCurrentlyPlayingIndexNative(
325+
JNIEnv *env,
326+
jobject) {
327+
return player.getCurrentlyPlayingIndex();
328+
}
329+
290330
#ifdef __cplusplus
291331
}
292332
#endif
333+

samples/powerplay/src/main/cpp/PowerPlayMultiPlayer.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,3 +234,11 @@ int32_t PowerPlayMultiPlayer::getBufferCapacityInFrames() {
234234

235235
return mAudioStream->getBufferCapacityInFrames();
236236
}
237+
238+
bool PowerPlayMultiPlayer::isOffloaded() {
239+
if (mAudioStream == nullptr) {
240+
return false;
241+
}
242+
243+
return mAudioStream->getPerformanceMode() == PerformanceMode::PowerSavingOffloaded;
244+
}

samples/powerplay/src/main/cpp/PowerPlayMultiPlayer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ class PowerPlayMultiPlayer : public iolib::SimpleMultiPlayer {
5050

5151
int32_t getBufferCapacityInFrames();
5252

53+
bool isOffloaded();
54+
5355
private:
5456
class MyPresentationCallback : public oboe::AudioStreamPresentationCallback {
5557
public:

0 commit comments

Comments
 (0)