it continues

This commit is contained in:
David Rose 2009-06-24 03:29:08 +00:00
parent a6c1759080
commit 8a48e4593e
15 changed files with 324 additions and 28 deletions

View File

@ -29,12 +29,15 @@ int P3DInstance::_next_instance_id = 0;
// Description:
////////////////////////////////////////////////////////////////////
P3DInstance::
P3DInstance(P3D_request_ready_func *func,
P3DInstance(P3D_request_ready_func *func, void *user_data,
const string &p3d_filename,
const P3D_token tokens[], size_t num_tokens) :
_func(func),
_fparams(p3d_filename, tokens, num_tokens)
{
_user_data = user_data;
_request_pending = false;
_instance_id = _next_instance_id;
++_next_instance_id;
@ -169,9 +172,13 @@ P3D_request *P3DInstance::
get_request() {
P3D_request *result = NULL;
ACQUIRE_LOCK(_request_lock);
nout << "P3DInstance::get_request() called on " << this
<< ", " << _pending_requests.size() << " requests in queue\n";
if (!_pending_requests.empty()) {
result = _pending_requests.front();
nout << "popped request " << result << "\n";
_pending_requests.pop_front();
_request_pending = !_pending_requests.empty();
}
RELEASE_LOCK(_request_lock);
@ -186,13 +193,21 @@ get_request() {
////////////////////////////////////////////////////////////////////
void P3DInstance::
add_request(P3D_request *request) {
nout << "adding a request\n";
nout << "adding request " << request << " in " << this << "\n";
assert(request->_instance == this);
ACQUIRE_LOCK(_request_lock);
_pending_requests.push_back(request);
_request_pending = true;
RELEASE_LOCK(_request_lock);
// Asynchronous notification for anyone who cares.
nout << "request_ready, calling " << _func << "\n" << flush;
if (_func != NULL) {
_func(this);
}
// Synchronous notification for pollers.
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
inst_mgr->signal_request_ready();
}

View File

@ -35,7 +35,7 @@ class P3DPackage;
////////////////////////////////////////////////////////////////////
class P3DInstance : public P3D_instance {
public:
P3DInstance(P3D_request_ready_func *func,
P3DInstance(P3D_request_ready_func *func, void *user_data,
const string &p3d_filename,
const P3D_token tokens[], size_t num_tokens);
~P3DInstance();

View File

@ -112,9 +112,10 @@ initialize() {
////////////////////////////////////////////////////////////////////
P3DInstance *P3DInstanceManager::
create_instance(P3D_request_ready_func *func,
void *user_data,
const string &p3d_filename,
const P3D_token tokens[], size_t num_tokens) {
P3DInstance *inst = new P3DInstance(func, p3d_filename,
P3DInstance *inst = new P3DInstance(func, user_data, p3d_filename,
tokens, num_tokens);
_instances.insert(inst);

View File

@ -45,6 +45,7 @@ public:
P3DInstance *
create_instance(P3D_request_ready_func *func,
void *user_data,
const string &p3d_filename,
const P3D_token tokens[], size_t num_tokens);

View File

@ -70,6 +70,7 @@ P3D_free_string(char *string) {
P3D_instance *
P3D_create_instance(P3D_request_ready_func *func,
void *user_data,
const char *p3d_filename,
const P3D_token tokens[], size_t num_tokens) {
assert(P3DInstanceManager::get_global_ptr()->is_initialized());
@ -80,7 +81,7 @@ P3D_create_instance(P3D_request_ready_func *func,
}
P3DInstance *result =
inst_mgr->create_instance(func, p3d_filename, tokens, num_tokens);
inst_mgr->create_instance(func, user_data, p3d_filename, tokens, num_tokens);
RELEASE_LOCK(_lock);
return result;
}
@ -148,7 +149,9 @@ P3D_request *
P3D_instance_get_request(P3D_instance *instance) {
assert(P3DInstanceManager::get_global_ptr()->is_initialized());
ACQUIRE_LOCK(_lock);
nout << "P3D_instance_get_request(" << instance << ")\n";
P3D_request *result = ((P3DInstance *)instance)->get_request();
nout << " result = " << result << "\n" << flush;
RELEASE_LOCK(_lock);
return result;
}
@ -160,6 +163,8 @@ P3D_check_request(bool wait) {
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
P3D_instance *inst = inst_mgr->check_request();
nout << "P3D_instance_check_request, inst = " << inst << "\n";
if (inst != NULL || !wait) {
RELEASE_LOCK(_lock);
return inst;
@ -192,13 +197,14 @@ P3D_instance_feed_url_stream(P3D_instance *instance, int unique_id,
P3D_result_code result_code,
int http_status_code,
size_t total_expected_data,
const unsigned char *this_data,
const void *this_data,
size_t this_data_size) {
assert(P3DInstanceManager::get_global_ptr()->is_initialized());
ACQUIRE_LOCK(_lock);
bool result = ((P3DInstance *)instance)->
feed_url_stream(unique_id, result_code, http_status_code,
total_expected_data, this_data, this_data_size);
total_expected_data,
(const unsigned char *)this_data, this_data_size);
RELEASE_LOCK(_lock);
return result;
}

View File

@ -111,11 +111,16 @@ P3D_free_string_func(char *string);
instances operate generally independently of each other. */
/* This structure defines the handle to a single instance. The host
may access the _request_pending member, which will be true if the
host should call P3D_instance_get_request(). */
may access any members appearing here. */
typedef struct {
/* true if the host should call P3D_instance_get_request().*/
bool _request_pending;
/* an opaque pointer the host may use to store private data that the
plugin does not interpret. This pointer can be directly set, or
it can be initialized in the P3D_create_instance() call. */
void *_user_data;
/* Additional opaque data may be stored here. */
} P3D_instance;
@ -199,6 +204,12 @@ typedef struct {
instance. If this is empty or NULL, the "src" token (below) will
be downloaded instead.
The user_data pointer is any arbitrary pointer value; it will be
copied into the _user_data member of the new P3D_instance object.
This pointer is intended for the host to use to store private data
associated with each instance; the plugin will not do anything with
this data.
For tokens, pass an array of P3D_token elements (above), which
correspond to the user-supplied keyword/value pairs that may appear
in the embed token within the HTML syntax; the host is responsible
@ -222,6 +233,7 @@ typedef struct {
typedef P3D_instance *
P3D_create_instance_func(P3D_request_ready_func *func,
void *user_data,
const char *p3d_filename,
const P3D_token tokens[], size_t num_tokens);
@ -446,7 +458,7 @@ P3D_instance_feed_url_stream_func(P3D_instance *instance, int unique_id,
P3D_result_code result_code,
int http_status_code,
size_t total_expected_data,
const unsigned char *this_data,
const void *this_data,
size_t this_data_size);

View File

@ -30,6 +30,7 @@
#if $[WINDOWS_PLATFORM]
#define WIN_RESOURCE_FILE nppanda3d.rc
#define LINKER_DEF_FILE nppanda3d.def
#define WIN_SYS_LIBS user32.lib
#endif
// Mac-specific options.

View File

@ -21,7 +21,8 @@
inline PPDownloadRequest::
PPDownloadRequest(RequestType rtype, int user_id) :
_rtype(rtype),
_user_id(user_id)
_user_id(user_id),
_notified_done(false)
{
}

View File

@ -13,3 +13,4 @@
////////////////////////////////////////////////////////////////////
#include "ppDownloadRequest.h"

View File

@ -36,6 +36,10 @@ public:
public:
RequestType _rtype;
int _user_id;
// This is sent true when we have notified the plugin that the
// stream is done.
bool _notified_done;
};
#include "ppDownloadRequest.I"

View File

@ -13,6 +13,7 @@
////////////////////////////////////////////////////////////////////
#include "ppInstance.h"
#include "startup.h"
#include "p3d_plugin_config.h"
////////////////////////////////////////////////////////////////////
@ -27,7 +28,7 @@ PPInstance::
PPInstance(NPMIMEType pluginType, NPP instance, uint16 mode,
int16 argc, char *argn[], char *argv[], NPSavedData *saved) {
logfile << "constructing " << this << "\n" << flush;
_inst = NULL;
_p3d_inst = NULL;
_npp_instance = instance;
_npp_mode = mode;
@ -69,9 +70,9 @@ PPInstance::
logfile
<< "destructing " << this << "\n" << flush;
if (_inst != NULL) {
P3D_instance_finish(_inst);
_inst = NULL;
if (_p3d_inst != NULL) {
P3D_instance_finish(_p3d_inst);
_p3d_inst = NULL;
}
// Free the tokens we allocated.
@ -101,7 +102,7 @@ set_window(NPWindow *window) {
_window = *window;
_got_window = true;
if (_inst == NULL) {
if (_p3d_inst == NULL) {
create_instance();
} else {
send_window();
@ -139,6 +140,12 @@ new_stream(NPMIMEType type, NPStream *stream, bool seekable, uint16 *stype) {
*stype = NP_ASFILEONLY;
return NPERR_NO_ERROR;
case PPDownloadRequest::RT_user:
// This is a request from the plugin. We'll receive this as a
// stream.
*stype = NP_NORMAL;
return NPERR_NO_ERROR;
default:
// Don't know what this is.
logfile << "Unexpected request " << (int)req->_rtype << "\n";
@ -147,6 +154,35 @@ new_stream(NPMIMEType type, NPStream *stream, bool seekable, uint16 *stype) {
return NPERR_GENERIC_ERROR;
}
////////////////////////////////////////////////////////////////////
// Function: PPInstance::write_stream
// Access: Public
// Description: Called by the browser to feed data read from a URL or
// whatever.
////////////////////////////////////////////////////////////////////
int PPInstance::
write_stream(NPStream *stream, int offset, int len, void *buffer) {
if (stream->notifyData == NULL) {
logfile << "Unexpected write_stream on " << stream->url << "\n";
return 0;
}
PPDownloadRequest *req = (PPDownloadRequest *)(stream->notifyData);
switch (req->_rtype) {
case PPDownloadRequest::RT_user:
P3D_instance_feed_url_stream(_p3d_inst, req->_user_id,
P3D_RC_in_progress, 0,
stream->end, buffer, len);
return len;
default:
logfile << "Unexpected write_stream on " << stream->url << "\n";
break;
}
return 0;
}
////////////////////////////////////////////////////////////////////
// Function: PPInstance::destroy_stream
// Access: Public
@ -156,6 +192,37 @@ new_stream(NPMIMEType type, NPStream *stream, bool seekable, uint16 *stype) {
////////////////////////////////////////////////////////////////////
NPError PPInstance::
destroy_stream(NPStream *stream, NPReason reason) {
if (stream->notifyData == NULL) {
logfile << "Unexpected destroy_stream on " << stream->url << "\n";
return NPERR_GENERIC_ERROR;
}
PPDownloadRequest *req = (PPDownloadRequest *)(stream->notifyData);
switch (req->_rtype) {
case PPDownloadRequest::RT_user:
{
P3D_result_code result_code = P3D_RC_done;
if (reason != NPRES_DONE) {
result_code = P3D_RC_generic_error;
}
assert(!req->_notified_done);
P3D_instance_feed_url_stream(_p3d_inst, req->_user_id,
result_code, 0, stream->end, NULL, 0);
req->_notified_done = true;
}
break;
case PPDownloadRequest::RT_core_dll:
// This is the one case we don't start with GetUrlNotify, so we'll
// never get a url_notify call on this one. So, we have to delete
// the PPDownloadRequest object here.
delete req;
break;
default:
break;
}
return NPERR_NO_ERROR;
}
@ -169,6 +236,36 @@ destroy_stream(NPStream *stream, NPReason reason) {
////////////////////////////////////////////////////////////////////
void PPInstance::
url_notify(const char *url, NPReason reason, void *notifyData) {
if (notifyData == NULL) {
return;
}
PPDownloadRequest *req = (PPDownloadRequest *)notifyData;
switch (req->_rtype) {
case PPDownloadRequest::RT_user:
if (!req->_notified_done) {
// We shouldn't have gotten here without notifying the stream
// unless the stream never got started (and hence we never
// called destroy_stream().
logfile << "Failure starting stream\n" << flush;
assert(reason != NPRES_DONE);
P3D_instance_feed_url_stream(_p3d_inst, req->_user_id,
P3D_RC_generic_error, 0, 0, NULL, 0);
req->_notified_done = true;
}
break;
case PPDownloadRequest::RT_core_dll:
// Shouldn't be possible to get here.
assert(false);
break;
default:
break;
}
delete req;
}
////////////////////////////////////////////////////////////////////
@ -189,6 +286,8 @@ stream_as_file(NPStream *stream, const char *fname) {
// Safari seems to want to report the filename in the old-style form
// "Macintosh HD:blah:blah:blah" instead of the new-style form
// "/blah/blah/blah". How annoying.
// TODO: Is "Macintosh HD:" the only possible prefix?
if (filename.substr(0, 13) == "Macintosh HD:") {
string fname2;
for (size_t p = 12; p < filename.size(); ++p) {
@ -212,6 +311,7 @@ stream_as_file(NPStream *stream, const char *fname) {
logfile << "got plugin\n";
if (!load_plugin(filename)) {
logfile << "Unable to launch core API.\n";
break;
}
create_instance();
break;
@ -230,6 +330,54 @@ stream_as_file(NPStream *stream, const char *fname) {
}
}
////////////////////////////////////////////////////////////////////
// Function: PPInstance::handle_request
// Access: Public
// Description: Handles a request from the plugin, forwarding
// it to the browser as appropriate.
////////////////////////////////////////////////////////////////////
void PPInstance::
handle_request(P3D_request *request) {
logfile << "handle_request: " << request << "\n";
assert(request->_instance == _p3d_inst);
bool handled = false;
switch (request->_request_type) {
case P3D_RT_stop:
logfile << "Got P3D_RT_stop\n";
if (_p3d_inst != NULL) {
P3D_instance_finish(_p3d_inst);
_p3d_inst = NULL;
}
// Guess the browser doesn't really care.
handled = true;
break;
case P3D_RT_get_url:
{
logfile << "Got P3D_RT_get_url: " << request->_request._get_url._url
<< "\n";
PPDownloadRequest *req =
new PPDownloadRequest(PPDownloadRequest::RT_user,
request->_request._get_url._unique_id);
browser->geturlnotify(_npp_instance, request->_request._get_url._url,
NULL, req);
}
break;
default:
// Some request types are not handled.
logfile << "Unhandled request: " << request->_request_type << "\n";
break;
};
P3D_request_finish(request, handled);
}
////////////////////////////////////////////////////////////////////
// Function: PPInstance::create_instance
// Access: Private
@ -238,7 +386,7 @@ stream_as_file(NPStream *stream, const char *fname) {
////////////////////////////////////////////////////////////////////
void PPInstance::
create_instance() {
if (_inst != NULL) {
if (_p3d_inst != NULL) {
// Already created.
return;
}
@ -263,10 +411,10 @@ create_instance() {
tokens = &_tokens[0];
}
_inst = P3D_create_instance
(NULL, _p3d_filename.c_str(), tokens, _tokens.size());
_p3d_inst = P3D_create_instance
(request_ready, this, _p3d_filename.c_str(), tokens, _tokens.size());
if (_inst != NULL) {
if (_p3d_inst != NULL) {
send_window();
}
}
@ -280,7 +428,7 @@ create_instance() {
////////////////////////////////////////////////////////////////////
void PPInstance::
send_window() {
assert(_inst != NULL);
assert(_p3d_inst != NULL);
P3D_window_handle parent_window;
#ifdef _WIN32
@ -288,7 +436,7 @@ send_window() {
#endif
P3D_instance_setup_window
(_inst, P3D_WT_embedded,
(_p3d_inst, P3D_WT_toplevel,
_window.x, _window.y, _window.width, _window.height,
parent_window);
}

View File

@ -35,10 +35,13 @@ public:
void set_window(NPWindow *window);
NPError new_stream(NPMIMEType type, NPStream *stream,
bool seekable, uint16 *stype);
int write_stream(NPStream *stream, int offset, int len, void *buffer);
NPError destroy_stream(NPStream *stream, NPReason reason);
void url_notify(const char *url, NPReason reason, void *notifyData);
void stream_as_file(NPStream *stream, const char *fname);
void handle_request(P3D_request *request);
private:
void create_instance();
void send_window();
@ -56,7 +59,7 @@ private:
bool _got_window;
NPWindow _window;
P3D_instance *_inst;
P3D_instance *_p3d_inst;
};
#include "ppInstance.I"

View File

@ -14,6 +14,7 @@
#include "startup.h"
#include "p3d_plugin_config.h"
#include "p3d_lock.h"
#ifdef _WIN32
#include <malloc.h>
@ -31,7 +32,85 @@ open_logfile() {
logfile_is_open = true;
}
}
#ifdef _WIN32
UINT _timer = 0;
#endif
LOCK _timer_lock;
////////////////////////////////////////////////////////////////////
// Function: handle_request_loop
// Description: Checks for any new requests from the plugin. This
// function is called only in the main thread.
////////////////////////////////////////////////////////////////////
static void
handle_request_loop() {
assert(is_plugin_loaded());
P3D_instance *p3d_inst = P3D_check_request(false);
logfile << "P3D_check_request() returns " << p3d_inst << "\n" << flush;
while (p3d_inst != (P3D_instance *)NULL) {
P3D_request *request = P3D_instance_get_request(p3d_inst);
logfile << "got request " << request << "\n";
if (request != (P3D_request *)NULL) {
PPInstance *inst = (PPInstance *)(p3d_inst->_user_data);
assert(inst != NULL);
inst->handle_request(request);
}
p3d_inst = P3D_check_request(false);
logfile << "P3D_check_request() returns " << p3d_inst << "\n" << flush;
}
}
////////////////////////////////////////////////////////////////////
// Function: win_timer_func
// Description: The Windows flavor of the timer callback function.
////////////////////////////////////////////////////////////////////
#ifdef _WIN32
static VOID CALLBACK
win_timer_func(HWND hwnd, UINT msg, UINT_PTR event, DWORD time) {
ACQUIRE_LOCK(_timer_lock);
logfile
<< "win_timer_func " << hwnd << ", " << msg << ", " << event
<< ", " << time << "\n"
<< "timer thread = " << GetCurrentThreadId() << "\n"
<< flush;
KillTimer(NULL, _timer);
_timer = 0;
RELEASE_LOCK(_timer_lock);
handle_request_loop();
}
#endif // _WIN32
////////////////////////////////////////////////////////////////////
// Function: request_ready
// Description: This function is attached as an asyncronous callback
// to each instance; it will be notified when the
// instance has a request ready. This function may be
// called in a sub-thread.
////////////////////////////////////////////////////////////////////
void
request_ready(P3D_instance *instance) {
logfile
<< "request_ready"
// << " thread = " << GetCurrentThreadId()
<< "\n" << flush;
// Since we might be in a sub-thread at this point, use a timer to
// forward this event to the main thread.
ACQUIRE_LOCK(_timer_lock);
#ifdef _WIN32
if (_timer == 0) {
_timer = SetTimer(NULL, 0, 0, win_timer_func);
logfile << "_timer = " << _timer << "\n" << flush;
}
#endif
RELEASE_LOCK(_timer_lock);
}
////////////////////////////////////////////////////////////////////
// Function: NP_Initialize
// Description: This function is called (almost) before any other
@ -56,9 +135,12 @@ NP_Initialize(NPNetscapeFuncs *browserFuncs,
open_logfile();
logfile << "initializing\n" << flush;
// logfile << "main thread = " << GetCurrentThreadId() << "\n";
logfile << "browserFuncs = " << browserFuncs << "\n" << flush;
INIT_LOCK(_timer_lock);
/*
#ifdef _WIN32
string plugin_location = "c:/cygwin/home/drose/player/direct/built/lib/p3d_plugin.dll";
@ -116,6 +198,17 @@ NP_GetEntryPoints(NPPluginFuncs *pluginFuncs) {
NPError OSCALL
NP_Shutdown(void) {
logfile << "shutdown\n" << flush;
ACQUIRE_LOCK(_timer_lock);
#ifdef _WIN32
if (_timer != 0) {
KillTimer(NULL, _timer);
_timer = 0;
}
#endif
RELEASE_LOCK(_timer_lock);
DESTROY_LOCK(_timer_lock);
unload_plugin();
// Not clear whether there's a return value or not. Some versions
@ -224,7 +317,10 @@ NPP_DestroyStream(NPP instance, NPStream *stream, NPReason reason) {
int32
NPP_WriteReady(NPP instance, NPStream *stream) {
logfile << "WriteReady\n";
return 0;
// We're supposed to return the maximum amount of data the plugin is
// prepared to handle. Gee, I don't know. As much as you can give
// me, I guess.
return 0x7fffffff;
}
////////////////////////////////////////////////////////////////////
@ -236,8 +332,13 @@ NPP_WriteReady(NPP instance, NPStream *stream) {
int32
NPP_Write(NPP instance, NPStream *stream, int32 offset,
int32 len, void *buffer) {
logfile << "Write\n";
return 0;
logfile << "Write " << stream->url
<< ", " << len << "\n" << flush;
PPInstance *inst = (PPInstance *)(instance->pdata);
assert(inst != NULL);
return inst->write_stream(stream, offset, len, buffer);
}
////////////////////////////////////////////////////////////////////

View File

@ -29,4 +29,6 @@ extern "C" {
NPError OSCALL NP_Shutdown(void);
}
void request_ready(P3D_instance *instance);
#endif

View File

@ -262,7 +262,7 @@ create_instance(const string &arg, P3D_window_type window_type,
}
P3D_instance *inst = P3D_create_instance
(NULL, os_p3d_filename.c_str(), tokens, num_tokens);
(NULL, NULL, os_p3d_filename.c_str(), tokens, num_tokens);
P3D_instance_setup_window
(inst, window_type, win_x, win_y, win_width, win_height, parent_window);