377 lines
6.6 KiB
C++
377 lines
6.6 KiB
C++
#include "SeekLayer.h"
|
|
#include "Main.h"
|
|
#include "output/AudioOut.h"
|
|
#include "util.h"
|
|
#include <assert.h>
|
|
using namespace Nullsoft::Utility;
|
|
|
|
struct OpenThreadData
|
|
{
|
|
IWMReaderCallback *callback;
|
|
wchar_t *url;
|
|
IWMReader *reader;
|
|
|
|
void open()
|
|
{
|
|
reader->Open(url, callback, 0);
|
|
}
|
|
|
|
OpenThreadData(IWMReader *_reader, const wchar_t *_url, IWMReaderCallback *_callback)
|
|
{
|
|
reader = _reader;
|
|
reader->AddRef();
|
|
callback = _callback;
|
|
callback->AddRef();
|
|
|
|
url = _wcsdup(_url);
|
|
}
|
|
|
|
~OpenThreadData()
|
|
{
|
|
free(url);
|
|
reader->Release();
|
|
callback->Release();
|
|
}
|
|
};
|
|
DWORD WINAPI OpenThread(void *param)
|
|
{
|
|
OpenThreadData *data = (OpenThreadData *)param;
|
|
data->open();
|
|
delete data;
|
|
return 0;
|
|
}
|
|
|
|
#define NEW_SEEK
|
|
SeekLayer::SeekLayer(IWMReader *_reader, ClockLayer *_clock)
|
|
: seekPos(0), reader(_reader), playState(PLAYSTATE_CLOSED), metadata(NULL), clock(_clock),
|
|
needPause(false), paused(false), needStop(false),
|
|
seekGuard(GUARDNAME("Seek Guard")),
|
|
oldState_buffer(PLAYSTATE_NONE)
|
|
{
|
|
reader->AddRef();
|
|
reader->QueryInterface(&reader2);
|
|
}
|
|
|
|
void SeekLayer::DoStop()
|
|
{
|
|
if (paused)
|
|
reader->Resume();
|
|
|
|
reader->Stop();
|
|
First().Stopping();
|
|
First().Kill();
|
|
if (paused)
|
|
{
|
|
paused = false;
|
|
out->Pause(0);
|
|
}
|
|
needStop = false;
|
|
}
|
|
|
|
void SeekLayer::SeekTo(long position)
|
|
{
|
|
AutoLock lock (seekGuard LOCKNAME("SeekTo"));
|
|
if (paused)
|
|
{
|
|
reader->Resume();
|
|
}
|
|
First().Stopping();
|
|
First().Kill();
|
|
seekPos = position;
|
|
clock->SetLastOutputTime(position);
|
|
clock->SetStartTimeMilliseconds(position);
|
|
out->Flush(position);
|
|
QWORD qSeekPos = position;
|
|
qSeekPos *= 10000;
|
|
reader->Start(qSeekPos, 0, 1.0f, NULL);
|
|
if (paused)
|
|
{
|
|
reader->Pause();
|
|
}
|
|
}
|
|
|
|
void SeekLayer::Pause()
|
|
{
|
|
AutoLock lock (seekGuard LOCKNAME("Pause"));
|
|
if (playState == PLAYSTATE_STARTED)
|
|
{
|
|
paused = true;
|
|
reader->Pause();
|
|
out->Pause(1);
|
|
}
|
|
else
|
|
{
|
|
needPause = true;
|
|
}
|
|
}
|
|
|
|
int SeekLayer::Open(const wchar_t *filename, IWMReaderCallback *callback)
|
|
{
|
|
AutoLock lock (seekGuard LOCKNAME("Open"));
|
|
assert(playState == PLAYSTATE_CLOSED);
|
|
needStop = false;
|
|
playState = PLAYSTATE_OPENING;
|
|
DWORD dummyId;
|
|
CreateThread(NULL, 0, OpenThread, new OpenThreadData(reader, filename, callback), 0, &dummyId);
|
|
return 0;
|
|
}
|
|
|
|
void SeekLayer::Stop()
|
|
{
|
|
AutoLock lock (seekGuard LOCKNAME("Stop"));
|
|
needStop = true;
|
|
|
|
switch (playState)
|
|
{
|
|
case PLAYSTATE_BUFFERING:
|
|
// needStop=false;
|
|
reader2->StopBuffering();
|
|
// reader->Stop();
|
|
break;
|
|
|
|
case PLAYSTATE_OPENING:
|
|
// wait for it to open (or connect) and then we'll kill it there
|
|
break;
|
|
|
|
case PLAYSTATE_NONE:
|
|
case PLAYSTATE_STOPPED:
|
|
if (FAILED(reader->Close())) // reader->Close() is sometimes synchronous, and sometimes not valid here
|
|
{
|
|
playState = PLAYSTATE_CLOSED;
|
|
return ;
|
|
}
|
|
break;
|
|
|
|
case PLAYSTATE_OPENED:
|
|
case PLAYSTATE_STARTED:
|
|
reader->Stop();
|
|
First().Stopping();
|
|
First().Kill();
|
|
break;
|
|
|
|
case PLAYSTATE_CLOSED:
|
|
needStop = false;
|
|
break;
|
|
/*
|
|
case PLAYSTATE_BUFFERING:
|
|
reader2->StopBuffering();
|
|
reader->Stop();
|
|
break;*/
|
|
|
|
case PLAYSTATE_SEEK:
|
|
break;
|
|
}
|
|
|
|
while (playState != PLAYSTATE_CLOSED)
|
|
{
|
|
lock.ManualUnlock();
|
|
Sleep(55);
|
|
lock.ManualLock(MANUALLOCKNAME("[Manual Lock]Stop"));
|
|
}
|
|
needStop = false;
|
|
}
|
|
|
|
void SeekLayer::Unpause()
|
|
{
|
|
AutoLock lock (seekGuard LOCKNAME("Unpause"));
|
|
if (playState == PLAYSTATE_STARTED)
|
|
{
|
|
paused = false;
|
|
out->Pause(0);
|
|
reader->Resume();
|
|
clock->Clock();
|
|
}
|
|
else
|
|
{
|
|
needPause = false;
|
|
}
|
|
}
|
|
|
|
void SeekLayer::Opened()
|
|
{
|
|
{
|
|
AutoLock lock (seekGuard LOCKNAME("SeekLayer::Opened"));
|
|
if (needStop)
|
|
{
|
|
playState = PLAYSTATE_OPENED;
|
|
lock.ManualUnlock();
|
|
reader->Close();
|
|
lock.ManualLock(MANUALLOCKNAME("[Manual Lock]SeekLayer::Opened"));
|
|
return ;
|
|
}
|
|
|
|
playState = PLAYSTATE_OPENED;
|
|
}
|
|
WMHandler::Opened();
|
|
}
|
|
|
|
void SeekLayer::Stopped()
|
|
{
|
|
{
|
|
AutoLock lock (seekGuard LOCKNAME("Stopped"));
|
|
if (needStop)
|
|
{
|
|
playState = PLAYSTATE_STOPPED;
|
|
lock.ManualUnlock();
|
|
reader->Close();
|
|
lock.ManualLock(MANUALLOCKNAME("Stopped"));
|
|
}
|
|
else
|
|
{
|
|
playState = PLAYSTATE_STOPPED;
|
|
}
|
|
|
|
WMHandler::Stopped();
|
|
}
|
|
}
|
|
|
|
void SeekLayer::Started()
|
|
{
|
|
{
|
|
AutoLock lock (seekGuard LOCKNAME("Started"));
|
|
playState = PLAYSTATE_STARTED;
|
|
|
|
if (needStop)
|
|
{
|
|
reader->Stop();
|
|
First().Stopping();
|
|
First().Kill();
|
|
return ;
|
|
}
|
|
else if (needPause)
|
|
{
|
|
Pause();
|
|
needPause = false;
|
|
}
|
|
}
|
|
WMHandler::Started();
|
|
}
|
|
|
|
void SeekLayer::Closed()
|
|
{
|
|
playState = PLAYSTATE_CLOSED;
|
|
paused = false;
|
|
needPause = false;
|
|
needStop = false;
|
|
seekPos = 0;
|
|
|
|
WMHandler::Closed();
|
|
}
|
|
|
|
void SeekLayer::BufferingStarted()
|
|
{
|
|
{
|
|
AutoLock lock (seekGuard LOCKNAME("BufferingStarted"));
|
|
if (playState == PLAYSTATE_OPENED)
|
|
oldState_buffer = PLAYSTATE_NONE;
|
|
else
|
|
oldState_buffer = playState;
|
|
if (playState != PLAYSTATE_STARTED)
|
|
playState = PLAYSTATE_BUFFERING;
|
|
if (needStop)
|
|
reader2->StopBuffering();
|
|
|
|
}
|
|
WMHandler::BufferingStarted();
|
|
}
|
|
|
|
|
|
void SeekLayer::BufferingStopped()
|
|
{
|
|
{
|
|
AutoLock lock (seekGuard LOCKNAME("BufferingStopped"));
|
|
if (needStop)
|
|
reader->Stop();
|
|
playState = oldState_buffer;
|
|
}
|
|
WMHandler::BufferingStopped();
|
|
}
|
|
|
|
|
|
void SeekLayer::EndOfFile()
|
|
{
|
|
{
|
|
AutoLock lock (seekGuard LOCKNAME("EndOfFile"));
|
|
if (needStop)
|
|
return ;
|
|
}
|
|
WMHandler::EndOfFile();
|
|
|
|
}
|
|
|
|
void SeekLayer::Connecting()
|
|
{
|
|
{
|
|
AutoLock lock (seekGuard LOCKNAME("SeekLayer::Connecting"));
|
|
if (needStop)
|
|
{
|
|
playState = PLAYSTATE_NONE;
|
|
lock.ManualUnlock();
|
|
reader->Close();
|
|
lock.ManualLock(MANUALLOCKNAME("[Manual Lock]SeekLayer::Connecting"));
|
|
return ;
|
|
}
|
|
playState = PLAYSTATE_NONE;
|
|
}
|
|
WMHandler::Connecting();
|
|
}
|
|
|
|
|
|
void SeekLayer::Locating()
|
|
{
|
|
{
|
|
AutoLock lock (seekGuard LOCKNAME("SeekLayer::Locating"));
|
|
if (needStop)
|
|
{
|
|
playState = PLAYSTATE_NONE;
|
|
lock.ManualUnlock();
|
|
reader->Close();
|
|
lock.ManualLock(MANUALLOCKNAME("[Manual Lock]SeekLayer::Locating"));
|
|
return ;
|
|
}
|
|
playState = PLAYSTATE_NONE;
|
|
}
|
|
WMHandler::Locating();
|
|
}
|
|
|
|
|
|
void SeekLayer::OpenCalled()
|
|
{
|
|
{
|
|
AutoLock lock (seekGuard LOCKNAME("SeekLayer::OpenCalled"));
|
|
if (needStop)
|
|
{
|
|
playState = PLAYSTATE_NONE;
|
|
lock.ManualUnlock();
|
|
reader->Close();
|
|
lock.ManualLock(MANUALLOCKNAME("[Manual Lock]SeekLayer::OpenCalled"));
|
|
return ;
|
|
}
|
|
|
|
playState = PLAYSTATE_NONE;
|
|
}
|
|
WMHandler::OpenCalled();
|
|
}
|
|
|
|
void SeekLayer::OpenFailed()
|
|
{
|
|
{
|
|
AutoLock lock (seekGuard LOCKNAME("SeekLayer::OpenFailed"));
|
|
if (playState == PLAYSTATE_OPENING)
|
|
playState = PLAYSTATE_NONE;
|
|
}
|
|
WMHandler::OpenFailed();
|
|
}
|
|
|
|
void SeekLayer::Error()
|
|
{
|
|
{
|
|
AutoLock lock (seekGuard LOCKNAME("SeekLayer::Error"));
|
|
/*if (playState == PLAYSTATE_OPENING)
|
|
playState = PLAYSTATE_CLOSED;
|
|
else */if (playState != PLAYSTATE_CLOSED)
|
|
playState = PLAYSTATE_NONE;
|
|
}
|
|
WMHandler::Error();
|
|
}
|