78 lines
3.0 KiB
C
78 lines
3.0 KiB
C
|
#pragma once
|
||
|
#include "PlaybackBase.h"
|
||
|
#include "foundation/error.h"
|
||
|
#include "service/api_service.h"
|
||
|
/* this one does most of the work for you.
|
||
|
It assumes blocking I/O and, generally, a simple implementation
|
||
|
You provide an implementation of PlaybackImpl */
|
||
|
|
||
|
class PlaybackBase2;
|
||
|
|
||
|
class PlaybackImpl
|
||
|
{
|
||
|
public:
|
||
|
void Connect(PlaybackBase2 *playback, ifc_playback_parameters *playback_parameters);
|
||
|
|
||
|
/* stuff you need to implement */
|
||
|
|
||
|
/* destructor. be diligent about closing stuff, can't guarantee that Close() got called beforehand */
|
||
|
virtual ~PlaybackImpl();
|
||
|
|
||
|
virtual ns_error_t Open(nx_uri_t filename)=0;
|
||
|
/* you need to handle the possibility that Close gets called more than one time */
|
||
|
virtual void Close()=0;
|
||
|
virtual bool IsSeekable()=0;
|
||
|
/* implementation note: add a reference (Retain) before assigning the value */
|
||
|
virtual ns_error_t GetMetadata(ifc_metadata **metadata)=0;
|
||
|
/* if you set *exact=false, GetLength will get called after the next DecodeStep */
|
||
|
virtual ns_error_t GetLength(double *length, bool *exact)=0;
|
||
|
/* only return an error if you're in a state you can't recover from.
|
||
|
if you can't seek, then just don't seek and return NErr_Success */
|
||
|
virtual ns_error_t Seek(const Agave_Seek *seek, ns_error_t *seek_error, double *new_position)=0;
|
||
|
/* return NErr_Success to continue
|
||
|
NErr_EndOfFile to indicate a natural end of file
|
||
|
otherwise return an error */
|
||
|
virtual ns_error_t DecodeStep()=0;
|
||
|
/* Save information and close the OS file handle.
|
||
|
fill resume_information with whatever information you'll need to resume */
|
||
|
virtual ns_error_t Interrupt(Agave_Seek *resume_information)=0;
|
||
|
/* During resume, be sure to call player->SetMetadata again */
|
||
|
virtual ns_error_t Resume(Agave_Seek *resume_information)=0;
|
||
|
protected:
|
||
|
|
||
|
PlaybackBase2 *playback;
|
||
|
ifc_playback_parameters *playback_parameters;
|
||
|
PlaybackImpl();
|
||
|
|
||
|
};
|
||
|
|
||
|
class PlaybackBase2 : public PlaybackBase
|
||
|
{
|
||
|
public:
|
||
|
PlaybackBase2();
|
||
|
~PlaybackBase2();
|
||
|
|
||
|
ns_error_t Initialize(api_service *service_manager, PlaybackImpl *implementation, nx_uri_t filename, ifc_player *player);
|
||
|
|
||
|
/* this two should ONLY be called from within your DecodeStep function! */
|
||
|
ns_error_t OpenOutput(const ifc_audioout::Parameters *parameters); // if this returns an error, return it from DecodeStep()
|
||
|
ns_error_t Output(const void *audio_data, size_t audio_data_length, double begin_position_seconds); // if this returns an error, return it from DecodeStep()
|
||
|
ns_error_t OutputNonInterleaved(const void *audio_data, size_t audio_data_length, double begin_position_seconds); // if this returns an error, return it from DecodeStep()
|
||
|
|
||
|
private:
|
||
|
static nx_thread_return_t NXTHREADCALL PlayerThreadFunction(nx_thread_parameter_t param);
|
||
|
nx_thread_return_t NXTHREADCALL DecodeLoop();
|
||
|
ns_error_t Init();
|
||
|
ns_error_t WaitForClose();
|
||
|
ns_error_t OutputWait();
|
||
|
ns_error_t Internal_Interrupt();
|
||
|
|
||
|
PlaybackImpl *implementation;
|
||
|
api_filelock *filelocker;
|
||
|
ifc_audioout *out;
|
||
|
bool paused;
|
||
|
double last_position;
|
||
|
bool exact_length;
|
||
|
ifc_audioout::Parameters parameters;
|
||
|
const uint8_t **output_pointers;
|
||
|
};
|