4 Commits

Author SHA1 Message Date
Michatec 0d0980a1ef refactor(radio): change Reverb indices to size_t 2026-04-05 19:14:57 +02:00
Michachatz ae215691ca Update radio.cpp 2026-04-05 19:09:43 +02:00
Michachatz 52f1a57de3 Update radio.cpp 2026-04-05 19:07:27 +02:00
Michatec 53abe918ca fix(player): improve cast player integration and service lifecycle management 2026-04-05 18:19:00 +02:00
2 changed files with 38 additions and 36 deletions
+25 -9
View File
@@ -92,18 +92,34 @@ public:
*/
class Reverb {
public:
std::vector<float> delayLine;
int pos = 0;
float feedback = 0.4f;
std::vector<float> d1, d2, d3;
size_t p1 = 0, p2 = 0, p3 = 0;
float feedback = 0.7f;
float mix = 0.0f;
Reverb() { delayLine.resize(4410, 0.0f); } // ~100ms
Reverb() {
d1.resize(11025, 0.0f); // 250ms
d2.resize(14700, 0.0f); // 333ms
d3.resize(17640, 0.0f); // 400ms
}
float process(float in) {
float delayed = delayLine[static_cast<size_t>(pos)];
delayLine[static_cast<size_t>(pos)] = in + delayed * feedback;
pos = (pos + 1) % static_cast<int>(delayLine.size());
return in + delayed * mix;
float y1 = d1[p1];
float y2 = d2[p2];
float y3 = d3[p3];
d1[p1] = in + y1 * feedback;
d2[p2] = in + y2 * feedback;
d3[p3] = in + y3 * feedback;
p1 = (p1 + 1) % d1.size();
p2 = (p2 + 1) % d2.size();
p3 = (p3 + 1) % d3.size();
float reverb = (y1 + y2 + y3) / 3.0f;
return in * (1.0f - mix) + reverb * mix;
}
};
@@ -189,4 +205,4 @@ Java_com_michatec_radio_helpers_NativeAudioProcessor_processAudio(JNIEnv *env, j
env->ReleaseShortArrayElements(data, buffer, 0);
}
} // extern "C"
} // extern "C"
@@ -156,7 +156,8 @@ class PlayerService : MediaLibraryService(), SharedPreferences.OnSharedPreferenc
castPlayer = CastPlayer.Builder(this).setLocalPlayer(exoPlayer).build()
// manually add seek to next and seek to previous since headphones issue them, and they are translated to next and previous station
player = object : ForwardingPlayer(exoPlayer) {
// IMPORTANT: Use castPlayer here instead of exoPlayer so the session controls both local and remote playback
player = object : ForwardingPlayer(castPlayer) {
override fun getAvailableCommands(): Player.Commands {
return super.getAvailableCommands().buildUpon().add(COMMAND_SEEK_TO_NEXT)
.add(COMMAND_SEEK_TO_PREVIOUS).build()
@@ -170,6 +171,7 @@ class PlayerService : MediaLibraryService(), SharedPreferences.OnSharedPreferenc
return C.TIME_UNSET // this will hide progress bar for HLS stations in the notification
}
}
player.addListener(playerListener)
}
@@ -483,35 +485,23 @@ class PlayerService : MediaLibraryService(), SharedPreferences.OnSharedPreferenc
isPlaying
)
if (isPlaying) {
// playback is active
} else {
if (!isPlaying) {
// cancel sleep timer
cancelSleepTimer()
// reset metadata
updateMetadata()
// playback is not active
// Not playing because playback is paused, ended, suppressed, or the player
// is buffering, stopped or failed. Check player.getPlayWhenReady,
// player.getPlaybackState, player.getPlaybackSuppressionReason and
// player.getPlaybackError for details.
// Check playback state to decide whether to stop the service
when (player.playbackState) {
// player is able to immediately play from its current position
Player.STATE_ENDED, Player.STATE_IDLE -> {
stopSelf()
}
Player.STATE_READY -> {
// Playback is paused. For radio, we can stop the service to remove the notification.
stopSelf()
}
// buffering - data needs to be loaded
Player.STATE_BUFFERING -> {
stopSelf()
}
// player finished playing all media
Player.STATE_ENDED -> {
stopSelf()
}
// initial state or player is stopped or playback failed
Player.STATE_IDLE -> {
stopSelf()
// DO NOT stop the service while buffering (especially important for Cast)
}
}
}
@@ -520,13 +510,9 @@ class PlayerService : MediaLibraryService(), SharedPreferences.OnSharedPreferenc
override fun onPlayWhenReadyChanged(playWhenReady: Boolean, reason: Int) {
super.onPlayWhenReadyChanged(playWhenReady, reason)
if (!playWhenReady) {
when (reason) {
Player.PLAY_WHEN_READY_CHANGE_REASON_END_OF_MEDIA_ITEM -> {
stopSelf()
}
else -> {
stopSelf()
}
// Only stop if not buffering and not ready to play (i.e. truly stopped/paused)
if (player.playbackState != Player.STATE_BUFFERING) {
stopSelf()
}
}
}