diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/replicant/nswasabi/PlaybackBase.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/replicant/nswasabi/PlaybackBase.cpp')
-rw-r--r-- | Src/replicant/nswasabi/PlaybackBase.cpp | 409 |
1 files changed, 409 insertions, 0 deletions
diff --git a/Src/replicant/nswasabi/PlaybackBase.cpp b/Src/replicant/nswasabi/PlaybackBase.cpp new file mode 100644 index 00000000..d3a94a6e --- /dev/null +++ b/Src/replicant/nswasabi/PlaybackBase.cpp @@ -0,0 +1,409 @@ +#include "PlaybackBase.h" +#include <stdlib.h> +#include <assert.h> +#ifdef __ANDROID__ +#include <android/log.h> // TODO: replace with generic logging API + +#else +#define ANDROID_LOG_INFO 0 +#define ANDROID_LOG_ERROR 1 +static void __android_log_print(int, const char *, const char *, ...) +{ +} +#endif +PlaybackBase::PlaybackBase() +{ + wake_flags=0; + last_wake_flags=0; + playback_thread=0; + secondary_parameters=0; + filename=0; + player=0; + queued_seek=0; + output_service=0; +} + +int PlaybackBase::Initialize(nx_uri_t filename, ifc_player *player) +{ + this->player = player; + this->filename = NXURIRetain(filename); + return NErr_Success; +} + +PlaybackBase::~PlaybackBase() +{ + if (secondary_parameters) + secondary_parameters->Release(); + if (filename) + NXURIRelease(filename); + if (queued_seek) + free(queued_seek); + if (playback_thread) + NXThreadJoin(playback_thread, 0); +} + +int PlaybackBase::Playback_Play(svc_output *output, ifc_playback_parameters *secondary_parameters) +{ + if (!playback_thread) + return 1; + + __android_log_print(ANDROID_LOG_INFO, "libreplicant", "[PlaybackBase] Play"); + + output_service = output; + threadloop_node_t *apc = thread_loop.GetAPC(); + if (apc) + { + this->secondary_parameters = secondary_parameters; + if (secondary_parameters) + secondary_parameters->Retain(); + + apc->func = APC_Play; + apc->param1 = this; + thread_loop.Schedule(apc); + return NErr_Success; + } + else + return NErr_OutOfMemory; +} + +int PlaybackBase::Playback_SeekSeconds(double seconds) +{ + __android_log_print(ANDROID_LOG_INFO, "libreplicant", "[PlaybackBase] Seek (%f seconds)", seconds); + Agave_Seek *seek = (Agave_Seek *)malloc(sizeof(Agave_Seek)); + if (seek) + { + seek->position_type = AGAVE_PLAYPOSITION_SECONDS; + seek->position.seconds = seconds; + threadloop_node_t *apc = thread_loop.GetAPC(); + if (apc) + { + apc->func = APC_Seek; + apc->param1 = this; + apc->param2 = seek; + thread_loop.Schedule(apc); + return NErr_Success; + } + } + free(seek); + return NErr_OutOfMemory; + +} + +int PlaybackBase::Playback_Pause() +{ + __android_log_print(ANDROID_LOG_INFO, "libreplicant", "[PlaybackBase] Pause"); + threadloop_node_t *apc = thread_loop.GetAPC(); + if (apc) + { + apc->func = APC_Pause; + apc->param1 = this; + thread_loop.Schedule(apc); + return NErr_Success; + } + else + return NErr_OutOfMemory; +} + +int PlaybackBase::Playback_Unpause() +{ + __android_log_print(ANDROID_LOG_INFO, "libreplicant", "[PlaybackBase] Unpause"); + threadloop_node_t *apc = thread_loop.GetAPC(); + if (apc) + { + apc->func = APC_Unpause; + apc->param1 = this; + thread_loop.Schedule(apc); + return NErr_Success; + } + else + return NErr_OutOfMemory; +} + +int PlaybackBase::Playback_Stop() +{ + __android_log_print(ANDROID_LOG_INFO, "libreplicant", "[PlaybackBase] Stop"); + threadloop_node_t *apc = thread_loop.GetAPC(); + if (apc) + { + apc->func = APC_Stop; + apc->param1 = this; + thread_loop.Schedule(apc); + return NErr_Success; + } + else + return NErr_OutOfMemory; +} + +int PlaybackBase::Playback_Close() +{ + __android_log_print(ANDROID_LOG_INFO, "libreplicant", "[PlaybackBase] Close"); + threadloop_node_t *apc = thread_loop.GetAPC(); + if (apc) + { + apc->func = APC_Close; + apc->param1 = this; + thread_loop.Schedule(apc); + return NErr_Success; + } + else + return NErr_OutOfMemory; +} + + +int PlaybackBase::FileLockCallback_Interrupt() +{ + __android_log_print(ANDROID_LOG_INFO, "libreplicant", "[PlaybackBase] Interrupt"); + threadloop_node_t *apc = thread_loop.GetAPC(); + if (apc) + { + apc->func = APC_Interrupt; + apc->param1 = this; + thread_loop.Schedule(apc); + return NErr_Success; + } + else + return NErr_OutOfMemory; +} + +void PlaybackBase::ToggleFlags(int wake_reason) +{ + switch(wake_reason) + { + case WAKE_KILL: + last_wake_flags ^= WAKE_KILL; /* toggle kill flag */ + break; + case WAKE_STOP: + last_wake_flags ^= WAKE_STOP; /* toggle stop flag */ + break; + case WAKE_PLAY: + last_wake_flags ^= WAKE_PLAY; /* toggle play flag */ + break; + case WAKE_PAUSE: + case WAKE_UNPAUSE: + last_wake_flags ^= WAKE_PAUSE; /* toggle pause flag */ + break; + case WAKE_INTERRUPT: + last_wake_flags ^= WAKE_INTERRUPT; /* toggle interrupt flag */ + break; + } +} + +int PlaybackBase::WakeReason(int mask) const +{ + int reason_awoken = last_wake_flags ^ wake_flags; + + reason_awoken = reason_awoken & mask; + + if (reason_awoken & WAKE_INTERRUPT) + { + if (wake_flags & WAKE_INTERRUPT) + return WAKE_INTERRUPT; + else + return WAKE_RESUME; + } + + if (reason_awoken & WAKE_STOP) + { + return WAKE_STOP; + } + + if (reason_awoken & WAKE_KILL) + { + return WAKE_KILL; + } + + if (reason_awoken & WAKE_PLAY) + { + if (wake_flags & WAKE_PLAY) + return WAKE_PLAY; + else /* if someone cleared the play flag for whatever reason, just treat it as a 0 */ + return 0; + } + + if (reason_awoken & WAKE_PAUSE) + { + if (wake_flags & WAKE_PAUSE) + return WAKE_PAUSE; + else + return WAKE_UNPAUSE; + } + + return 0; +} + +int PlaybackBase::Wake(int mask) +{ + assert(mask != 0); /* make sure they didn't specify a 0 mask (which would make this function potentially never return */ + assert((mask & WAKE_ALL_MASK) != 0); /* make sure it's a valid mask */ + + for (;;) + { + int reason_awoken = last_wake_flags ^ wake_flags; + reason_awoken = reason_awoken & mask; + + if (reason_awoken) + { + int ret = WakeReason(mask); + ToggleFlags(ret); // mark the last-known-state of the wake flags + + return ret; + + } + + if (((mask & WAKE_PLAY) && !(wake_flags & WAKE_PLAY))/* if we're stopped and they asked to be woken up for play */ + || ((mask & WAKE_PAUSE) && (wake_flags & WAKE_PAUSE)) /* or waiting to be woken up for unpause */ + || ((mask & WAKE_INTERRUPT) && (wake_flags & WAKE_INTERRUPT))) /* or waiting to be woken up for resume */ + { + thread_loop.Step(); + + int ret = WakeReason(mask); + if (ret) /* if ret is !0, it means we gotten woken up for a reason we care about */ + { + ToggleFlags(ret); // mark the last-known-state of the wake flags + return ret; + } + } + else /* no reason to sleep, so just return 0 (no change) */ + { + return 0; + } + } +} + +int PlaybackBase::Check(int mask) +{ + assert(mask != 0); /* make sure they didn't specify a 0 mask (which would make this function potentially never return */ + assert((mask & WAKE_ALL_MASK) != 0); /* make sure it's a valid mask */ + + int reason_awoken = last_wake_flags ^ wake_flags; + reason_awoken = reason_awoken & mask; + + int ret = 0; + if (reason_awoken) + { + ret = WakeReason(mask); + ToggleFlags(ret); // mark the last-known-state of the wake flags + } + return ret; +} + + +int PlaybackBase::Wait(unsigned int milliseconds, int mask) +{ + int reason_awoken = last_wake_flags ^ wake_flags; + reason_awoken = reason_awoken & mask; + + if (reason_awoken) + { + int ret = WakeReason(mask); + ToggleFlags(ret); // mark the last-known-state of the wake flags + + return ret; + } + + thread_loop.Step(milliseconds); + + int ret = WakeReason(mask); + ToggleFlags(ret); // mark the last-known-state of the wake flags + return ret; +} + +int PlaybackBase::Sleep(unsigned int milliseconds, int mask) +{ + int reason_awoken = last_wake_flags ^ wake_flags; + reason_awoken = reason_awoken & mask; + + if (reason_awoken) + { + int ret = WakeReason(mask); + assert(ret != 0); + + return ret; + + } + + thread_loop.Step(milliseconds); + + int ret = WakeReason(mask); + return ret; + +} + +void PlaybackBase::OnStopPlaying() +{ + // turn off the play flag (also adjust old wake flags so we don't trigger a WAKE_STOP) + __android_log_print(ANDROID_LOG_INFO, "libreplicant", "[PlaybackBase] OnStopPlaying"); + + wake_flags &= ~WAKE_PLAY; + last_wake_flags &= ~WAKE_PLAY; +} + +void PlaybackBase::OnInterrupted() +{ + __android_log_print(ANDROID_LOG_INFO, "libreplicant", "[PlaybackBase] OnInterrupted"); + + wake_flags &= ~WAKE_INTERRUPT; + last_wake_flags &= ~WAKE_INTERRUPT; +} + +Agave_Seek *PlaybackBase::GetSeek() +{ + Agave_Seek *seek = queued_seek; + queued_seek=0; + return seek; +} + +void PlaybackBase::FreeSeek(Agave_Seek *seek) +{ + free(seek); +} + +bool PlaybackBase::PendingSeek() +{ + return !!queued_seek; +} + +void PlaybackBase::APC_Play(void *_playback_base, void *param2, double real_value) +{ + PlaybackBase *playback_base = (PlaybackBase *)_playback_base; + playback_base->wake_flags |= WAKE_PLAY; +} + +void PlaybackBase::APC_Seek(void *_playback_base, void *_seek, double real_value) +{ + PlaybackBase *playback_base = (PlaybackBase *)_playback_base; + Agave_Seek *seek = (Agave_Seek *)_seek; + free(playback_base->queued_seek); + playback_base->queued_seek = seek; + +} + +void PlaybackBase::APC_Pause(void *_playback_base, void *param2, double real_value) +{ + PlaybackBase *playback_base = (PlaybackBase *)_playback_base; + playback_base->wake_flags |= WAKE_PAUSE; +} + +void PlaybackBase::APC_Unpause(void *_playback_base, void *param2, double real_value) +{ + PlaybackBase *playback_base = (PlaybackBase *)_playback_base; + playback_base->wake_flags &= ~WAKE_PAUSE; +} + +void PlaybackBase::APC_Stop(void *_playback_base, void *param2, double real_value) +{ + PlaybackBase *playback_base = (PlaybackBase *)_playback_base; + playback_base->wake_flags |= WAKE_STOP; +} + +void PlaybackBase::APC_Close(void *_playback_base, void *param2, double real_value) +{ + PlaybackBase *playback_base = (PlaybackBase *)_playback_base; + playback_base->wake_flags |= WAKE_KILL; +} + +void PlaybackBase::APC_Interrupt(void *_playback_base, void *param2, double real_value) +{ + PlaybackBase *playback_base = (PlaybackBase *)_playback_base; + playback_base->wake_flags |= WAKE_INTERRUPT; +} |