diff options
Diffstat (limited to 'Src/replicant/player')
-rw-r--r-- | Src/replicant/player/ifc_playback.h | 71 | ||||
-rw-r--r-- | Src/replicant/player/ifc_playback_parameters.h | 20 | ||||
-rw-r--r-- | Src/replicant/player/ifc_player.h | 93 | ||||
-rw-r--r-- | Src/replicant/player/svc_output.h | 40 | ||||
-rw-r--r-- | Src/replicant/player/types.h | 44 |
5 files changed, 268 insertions, 0 deletions
diff --git a/Src/replicant/player/ifc_playback.h b/Src/replicant/player/ifc_playback.h new file mode 100644 index 00000000..e208dd5a --- /dev/null +++ b/Src/replicant/player/ifc_playback.h @@ -0,0 +1,71 @@ +#pragma once +#include "foundation/dispatch.h" +#include "foundation/error.h" +#include "types.h" +#include "svc_output.h" +#include "ifc_playback_parameters.h" + +/* Note that since a typical ifc_playback implementation +is running on another thread, most functions will always succeed (except for out of memory or thread creation problems) +but might report an error later to the ifc_player object that was passed +when creating the playback object */ + +class NOVTABLE ifc_playback : public Wasabi2::Dispatchable +{ +protected: + ifc_playback() : Dispatchable(NUM_DISPATCH_CODES) {} + ~ifc_playback() {} +public: + /* optionally call Cue before calling Play to set the start and end positions + in a cuesheet situation, these will might also get called after + you indicate that cue end position has been reached */ + int Cue(Agave_PositionType position_type, Agave_Position start, Agave_Position end) { return Playback_Cue(position_type, start, end); } + // start only version of Cue + int CueStart(Agave_PositionType position_type, Agave_Position start) { return Playback_CueStart(position_type, start); } + + // begins playback. + int Play(svc_output *output, ifc_playback_parameters *secondary_parameters) { return Playback_Play(output, secondary_parameters); } + + int SeekSeconds(double seconds) { return Playback_SeekSeconds(seconds); } + + // called on user-initiated stop. not called if the playback object indiciated a stop (e.g. EOF) + int Stop() { return Playback_Stop(); } + + int Pause() { return Playback_Pause(); } + int Unpause() { return Playback_Unpause(); } + + /* called to shut things down. + note that if your playback object is in a 'stopped' state, + it should be prepared to receive Cue/Play call until Close() is called */ + int Close() { return Playback_Close(); } + + /* most of the time, you'll pass SetVolume and SetPan on to the output object + but some special-use playback objects (e.g. analog CD playback) might have to implement this */ + // 0 to 1.0 + int SetVolume(float volume) { return Playback_SetVolume(volume); } + // -1.0 to 1.0 + int SetPan(float pan) { return Playback_SetPan(pan); } + + /* most of the time, you'll ignore SetEQ + but some special-use playback objects (e.g. analog CD playback) might have to implement this */ + int SetEQ(float preamp, int num_bands, float *bands) { return Playback_SetEQ(preamp, num_bands, bands); } + + enum + { + NUM_DISPATCH_CODES, + }; + +protected: + virtual int WASABICALL Playback_Cue(Agave_PositionType position_type, Agave_Position start, Agave_Position end) { return NErr_NotImplemented; } + virtual int WASABICALL Playback_CueStart(Agave_PositionType position_type, Agave_Position start) { return NErr_NotImplemented; } + virtual int WASABICALL Playback_Play(svc_output *output, ifc_playback_parameters *secondary_parameters)=0; + virtual int WASABICALL Playback_SeekSeconds(double seconds)=0; + virtual int WASABICALL Playback_Stop()=0; + virtual int WASABICALL Playback_Pause()=0; + virtual int WASABICALL Playback_Unpause()=0; + virtual int WASABICALL Playback_Close()=0; + virtual int WASABICALL Playback_SetVolume(float volume) { return NErr_NotImplemented; } + virtual int WASABICALL Playback_SetPan(float pan) { return NErr_NotImplemented; } + virtual int WASABICALL Playback_SetEQ(float preamp, int num_bands, float *bands) { return NErr_NotImplemented; } +}; + diff --git a/Src/replicant/player/ifc_playback_parameters.h b/Src/replicant/player/ifc_playback_parameters.h new file mode 100644 index 00000000..1324b7d6 --- /dev/null +++ b/Src/replicant/player/ifc_playback_parameters.h @@ -0,0 +1,20 @@ +#pragma once +#include "foundation/dispatch.h" + +/* ifc_output_parameters abstracts output parameters that are passed to an input plugin + it is things that an input plugin wouldn't necessary know about + for example, is a playback object is being used for track preview, + it might be configured to play out of a different output device + and there's no way an input plugin would know that + */ +class NOVTABLE ifc_playback_parameters : public Wasabi2::Dispatchable +{ +protected: + ifc_playback_parameters() : Dispatchable(DISPATCHABLE_VERSION) {} + ~ifc_playback_parameters() {} + + enum + { + DISPATCHABLE_VERSION=0, + }; +}; diff --git a/Src/replicant/player/ifc_player.h b/Src/replicant/player/ifc_player.h new file mode 100644 index 00000000..368d8f74 --- /dev/null +++ b/Src/replicant/player/ifc_player.h @@ -0,0 +1,93 @@ +#pragma once +#include "foundation/dispatch.h" +#include "foundation/error.h" +#include "foundation/types.h" +#include "metadata/ifc_metadata.h" +#include "audio/ifc_equalizer.h" +#include "nx/nxuri.h" + +/* implemented by Winamp (or whatever application) +your ifc_playback implementation should call this with events + +TODO: benski> should we require the ifc_playback object to get passed in to each function? +*/ + +class NOVTABLE ifc_player : public Wasabi2::Dispatchable +{ +protected: + ifc_player() : Dispatchable(DISPATCHABLE_VERSION) {} + ~ifc_player() {} +public: + + /* When your playback object has read enough of the file to provide metadata + it should call this method. + It will be called for both song metadata (artist, album, etc) and codec metadata (bitrate, samplerate, etc). + so make sure you can provide both - this might mean you have to wait until the first frame is decoded. + The player object will add a reference in the function, and release whenever it is no longer needed (usually on start of next track) + */ + void SetMetadata(ifc_metadata *metadata) { Player_SetMetadata(metadata); } + + /* Call this just once (with timestamp=0) for CBR files or update continuously for VBR + bitrate should be in bits per second, e.g. 128000 (not 128!) + */ + void SetBitrate(uint64_t bitrate, double timestamp) { Player_SetBitrate(bitrate, timestamp); } + + /* Playback plugin should call this when it knows the length + can be updated if necessary (e.g. for VBR files w/o header) + If this is not called, it assumed to be a stream (radio) + */ + void SetLength(double length) { Player_SetLength(length); } + + /* Output plugin should call this every once in a while, + if your input plugin does its own audio output (e.g. analog CD) you should call this yourself + */ + void SetPosition(double timestamp) { Player_SetPosition(timestamp); } + + void OnLoaded(nx_uri_t filename) { Player_OnLoaded(filename); } + /* Input plugin should call this when playback ends at the end of the file + Do not call if playback stopped because of an error */ + void OnEndOfFile() { Player_OnEndOfFile(); } + + void OnError(NError code) { Player_OnError(code); } + + void OnStopped() { Player_OnStopped(); } + + void SetEqualizer(ifc_equalizer *equalizer) { return Player_SetEqualizer(equalizer); } + + /* percent is 0-100. setting to 100 implies that buffering has finished */ + void SetBufferStatus(int percent) { return Player_SetBufferStatus(percent); } + + void OnSeekComplete(int error_code, double new_position) { return Player_OnSeekComplete(error_code, new_position); } + + /* seekable is 0 (false) or 1 (true) */ + void SetSeekable(int seekable) { return Player_SetSeekable(seekable); } + + void AsynchronousFunctionCall(void (*function)(void *, void *, double), void *param1, void *param2, double real_param) { Player_AsynchronousFunctionCall(function, param1, param2, real_param); } + + /* Call this after you've successfully opened and parsed the playback file, and are attempting to start playback */ + void OnReady() { Player_OnReady(); }; + + /* Call this after EndOfFile() when either 1) You process an ifc_playback::Close() call or 2) ifc_audioout::IsPlaying() returns NErr_False while waiting for a Close() call */ + void OnClosed() { Player_OnClosed(); }; + + enum + { + DISPATCHABLE_VERSION, + }; +protected: + virtual void WASABICALL Player_SetMetadata(ifc_metadata *metadata) = 0; + virtual void WASABICALL Player_SetBitrate(uint64_t bitrate, double timestamp) = 0; + virtual void WASABICALL Player_SetLength(double length) = 0; + virtual void WASABICALL Player_SetPosition(double timestamp) = 0; + virtual void WASABICALL Player_OnLoaded(nx_uri_t filename) = 0; + virtual void WASABICALL Player_OnEndOfFile() = 0; + virtual void WASABICALL Player_OnError(NError code) = 0; + virtual void WASABICALL Player_OnStopped()=0; + virtual void WASABICALL Player_SetEqualizer(ifc_equalizer *equalizer)=0; + virtual void WASABICALL Player_SetBufferStatus(int percent)=0; + virtual void WASABICALL Player_OnSeekComplete(int error_code, double new_position)=0; + virtual void WASABICALL Player_SetSeekable(int seekable)=0; + virtual void WASABICALL Player_AsynchronousFunctionCall(void (*function)(void *, void *, double), void *param1, void *param2, double real_param)=0; + virtual void WASABICALL Player_OnReady()=0; + virtual void WASABICALL Player_OnClosed()=0; +}; diff --git a/Src/replicant/player/svc_output.h b/Src/replicant/player/svc_output.h new file mode 100644 index 00000000..264918a3 --- /dev/null +++ b/Src/replicant/player/svc_output.h @@ -0,0 +1,40 @@ +#pragma once +#include "foundation/dispatch.h" +#include "audio/ifc_audioout.h" +#include "player/ifc_playback_parameters.h" + +class ifc_player; + +// {FB5E9AE3-E033-407C-942B-6C1BFAF52A5C} +static const GUID output_service_guid = +{ 0xfb5e9ae3, 0xe033, 0x407c, { 0x94, 0x2b, 0x6c, 0x1b, 0xfa, 0xf5, 0x2a, 0x5c } }; + +class NOVTABLE svc_output : public Wasabi2::Dispatchable +{ +protected: + svc_output() : Dispatchable(DISPATCHABLE_VERSION) {} + ~svc_output() {} +public: + static GUID GetServiceType() { return output_service_guid; } + /* ----- Audio Output ----- */ + // Opens winamp2-style Audio Output - good for audio-only streams (buffered, push, output-plugin-defined buffersize) + int AudioOpen(const ifc_audioout::Parameters *format, ifc_player *player, ifc_playback_parameters *secondary_parameters, ifc_audioout **out_output) { return OutputService_AudioOpen(format, player, secondary_parameters, out_output); } + + /* ----- Video Output ----- */ + int VideoOpen(); + + /* ----- Text Output ----- */ + // Opens a subtitle stream + int TextOpenSubtitle(); + // Opens a video info text stream + int TextOpenInfo(); + // Opens a lyrics text stream + int TextOpenLyrics(); + + enum + { + DISPATCHABLE_VERSION, + }; +protected: + virtual int WASABICALL OutputService_AudioOpen(const ifc_audioout::Parameters *format, ifc_player *player, ifc_playback_parameters *secondary_parameters, ifc_audioout **out_output) = 0; +}; diff --git a/Src/replicant/player/types.h b/Src/replicant/player/types.h new file mode 100644 index 00000000..62a07104 --- /dev/null +++ b/Src/replicant/player/types.h @@ -0,0 +1,44 @@ +#pragma once +#include "foundation/types.h" + +enum Agave_PositionType +{ + AGAVE_PLAYPOSITION_100NANOECONDS = 0, + AGAVE_PLAYPOSITION_MILLISECONDS = 1, + AGAVE_PLAYPOSITION_SECONDS = 2, + AGAVE_PLAYPOSITION_HMSF= 3, + AGAVE_PLAYPOSITION_SAMPLE_FRAMES = 4, + AGAVE_PLAYPOSITION_BYTES = 5, + AGAVE_PLAYPOSITION_PACKETS = 6, +}; + +struct Agave_HMSF +{ + uint8_t hours; + uint8_t minutes; + uint8_t seconds; + uint8_t frames; +}; + +union Agave_Position +{ + uint64_t nanoseconds100; // in increments of 100 nanoseconds (microsoft style) + uint64_t milliseconds; + double seconds; + Agave_HMSF hmsf; + uint64_t sample_frames; + uint64_t bytes; + uint64_t packets; +}; + +struct Agave_Seek +{ + Agave_PositionType position_type; + Agave_Position position; +}; + +static void Agave_Seek_SetBytes(Agave_Seek *seek, uint64_t bytes) +{ + seek->position_type=AGAVE_PLAYPOSITION_BYTES; + seek->position.bytes = bytes; +} |