Skip navigation

Today We’ll implement a javascript callback interface in C++.

We’re targetting a browser plugin (Which already has a “one way” js interface).
The idea : we want the plugin to trigger javascript methods, and ultimately we want to be able to link any js code to our plugin events loop.

Note:This article requires some c++/Win32 api/netscape api skills as well as a tiny clue of what is discussed here…

When coding cross platform software , you’ll often have to write some parts of your plugin twice. (sometimes more than twice)
In this case, MS activex com objects aren’t handled the way nsi controls are, so we need to split the code.

our method(s) should have an input parameter, “name” that we will use to store our javascript function name we want to trigger.

so something like : return Our_JS_CallBack(const char * name)

when called from the plugin, this method will send client’s browser a js event that will spawn our function which name is has been inputed at call.

Please be carefull here : ClientSite and ClientInstance are declared and initialised out of this 2 functions.
both of these pointers should have a correct value before using ::Our_JS_CallBack

MicroSoft CODE: m_spClientSite is a pointer to oleclientsite of your plugin ( type : ComPtr )
NetScape CODE: ClientInstance is the netscape NPP object pointer for your plugin (type : NPP);

Microsoft style:

//————————————————————————–
HRESULT Plugin::Our_JS_CallBack(const char * name)
{
IOleClientSite *m_spClientSite = (IOleClientSite *)GetCClientSite();

IServiceProvider* isp;
IWebBrowser2* ppBrowser;

HRESULT hr = m_spClientSite->QueryInterface(IID_IServiceProvider, reinterpret_cast(&isp));
if(FAILED(hr)) return FALSE;

hr = isp->QueryService(IID_IWebBrowserApp, IID_IWebBrowser2, reinterpret_cast(&ppBrowser));
if(NULL==ppBrowser) return S_FALSE;

IDispatch *m_ppDispDoc;
hr = ppBrowser->get_Document(&m_ppDispDoc);
if(FAILED(hr)) return S_FALSE;

IHTMLDocument2 *ppDocument2;
hr = m_ppDispDoc->QueryInterface(IID_IHTMLDocument2 ,reinterpret_cast(&ppDocument2));
if(FAILED(hr)) return S_FALSE;

CComPtr scriptEngine;
ppDocument2->get_Script(&scriptEngine);

DISPID callid;
USES_CONVERSION;
OLECHAR FAR* szCallMember = T2OLE(name);
HRESULT hr3 = scriptEngine->GetIDsOfNames(IID_NULL, &szCallMember, 1, LOCALE_USER_DEFAULT, &callid);
DISPPARAMS callParameters = { 0 };
int nargs = 0;
callParameters.cArgs = nargs + 1;

CComPtr win;
ppDocument2->get_parentWindow(&win);

VARIANT *vargs= new VARIANT[nargs + 1];
VARIANT result;

vargs[nargs] = CComVariant(win);
long index;
callParameters.rgvarg = vargs;
EXCEPINFO exception;

HRESULT hr4 = scriptEngine->Invoke(callid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &callParameters, &result, &exception, 0);

return S_OK;
}

NetScape Style:

NPBool NSPlugin::Our_JS_CallBack(const char *name)
{
NPObject *window;
NPN_GetValue(ClientInstance, NPNVWindowNPObject, &window);
NPIdentifier methodName;
methodName= NPN_GetStringIdentifier(name);
uint32_t argCount=0;
NPVariant result;
NPN_Invoke( NsInstance,
window,
methodName,
NULL,
argCount,
&result);
return TRUE;
}

You ‘ll have to declare both methods in your plugin class and be carefull not to call Our_JS_CallBack in a loop !

ie (c++ code): instance->Our_JS_CallBack(“JSEvent”);

you can then go to your HTML code after plugin’s instanciation, and write down the body of your callback

function JSEvent()
{
alert(“well done!”)
}

when the plugin executes instance->Our_JS_CallBack(“JSEvent”), a nice alert box should appear on client side, validating the javascript callback.

The hard part was understanding the concept and digging msdn 🙂

Advertisements

A crucial question for all frontend developers is building both a clean and strong user interface.

This article will be usefull if you want to submit a new StreamPlug skin for a later integration.

A StreamPlug skin is made of several images that will be used by the player to render an interactive player controler. A C++ Class is then used to handle the skin’s controls positions/events.
We’ll first concern on the graphics involved, then we will see how they are used in the code

Final result:

Note:Streamplug player is required, you can download it here

We will be happy to see user submitted skins added to streamplug’s next releases, please send us a message !

STEP 1: Create a background set of images:

This part of the skin is divided in three parts as follow:

– Left part

– Middle 1 pixel part

– Right part

The 1 pixel part will be copied several times by the player when necessary to follow the skin ‘s width,
So that you can keep control’s and border’s integrity.
In this skin, both seek bar and volume bar are resized along with the skin, they should appear in the 1 pixel part.
Note that the background set is used to save static buttons.
Static Controls never need to be removed or hidden, so keeping them here is safe.

STEP 2 : Create a controls set of images:

Keep in mind these controls’ colors and sizes should respect the overall design

– Play button

– Pause button

An empty square must have been reserved in the background part to accept these 2 pictures

– Buffer image

This picture will be blitted on the background , accordingly to current streaming buffering state

– Seek button

This will be displayed in the seek bar and follow current media’s play position.

– Volume button

As for Seek button, this is a dragable control. It will overlay the volume bar.

– Volume label

One sample optionnal picture used in this skin to clarify the volume control’s position.

– Loop mode button

– Record button

STEP 4: Set absolute controls positions:

At this point we have all the graphics in hand but the player also needs to know the position of each element so that our flat bitmap becomes an interactive skin.
(For example, the pause button needs to be displayed at a very x,y coordinates on the skin, when the player is playing something.)

Here are some raw coordinates values for our black skin:

———————————————————————————-
Syntax:Element={x, y, width, height}//comments
———————————————————————————-
Back = {0 ,0 ,194 ,32} //size of the background’s left part
Play = {6 ,18 ,11 ,11} //position of the play-pause control
Stop = {21 ,17 ,10 ,10} //position of the stop control
Prev = {37 ,17 ,8 ,10} //position of the previous control
Next = {51 ,17 ,8 ,10} //position of the next control
Rec = {65,17 ,11 ,11} //position of the record
FullScren = {82 ,17 ,10 ,10} //position of the fullscreen control
Open = {100,16 ,11 ,11} //position of the open control
Buffer = {203,21 ,12 ,6} //position of the buffer control
PosBut = {5 ,5 ,19 ,8} //position of the seek cursor control (initial position)
VolBut = {128,19 ,11 ,8} //position of the volume cursor control (initial position)
LoopBut = {111,18 ,15 ,10} //position of the loop control
Vol = {130,14 ,47 ,6} //position of the volume label

STEP 5: Code and Release

This last and final part is up to us, that means you willl need to send us a mail if you want the dev team to take care of your request.

If we like your work, here’s a quick view of what’s done next :

The .bmp images files are converted to .h files with a batch script using bin2hc, then the new skin’s c++ class is added to the player’s core, including the new .h bitmaps.

This class is instanciated as the player launches, so changes have to be done here, as well as the skin selection parts of the code.

After a clean rebuild, the player can be launched and the new player can be used, as shown on top of this page for the black skin. 🙂

StreamPlug is an advanced media player for the web : It decodes MPEG4 video streams such as h264, and vorbis audio from a remote file using a simple http server.
This JQuery plugin will help you add a streamplug player on your website/blog, a single line is sufficient to display the player to the right size, and play the media on the fly, without any buffering time !

Streamplug installer:click here
Demo:click here
Download source: click here
Plugin Homepage:click here

Here is a demonstration on how to use it in your web contents:


STEP 0 : PREREQUISTES

– Jquery
– JStreamPlug plugin
– StreamPlug


STEP 1 : HEADER INCLUDES

<script type=’text/javascript’ src=’jquery.min.js’></script>
<script type=’text/javascript’ src=’jquery.JStreamPlug.js’></script>



STEP2 : ADD THE CONTROL TO YOUR HTML PAGE

<div class=”player”></div>



STEP 3 (FINAL) : CREATE A JSTREAMPLUG INSTANCE

<script>
$(‘div.player’).StreamPlug(‘http://sampleserver/samplefile&#8217;,720,400,’lite’);
</script>

Syntax : $(element).StreamPlug(url,width,height,skin_name);

Here are described some key functionalities you can run after calling the plugin:

//Get Attributes
/////////////////

//Get Plugin Window Width
$().SpvideoWindowWidth()

//Get Plugin Window Height
$().SpvideoWindowHeigth()

//Get Plugin Skin Width
$().SpskinW()

//Get Plugin Skin Height
$().SpskinH()

//Get Plugin Version Number
$().Spcurversion()

//Get current volume
$().Spvolume()

//Get current play position in kb
$().SpplayPositionKb()

//Get current play position in ms
$().SpplayPositionMs()

//Get current received stream kb amount
$().SpstreamPositionKb()

//Get current file lenght in kb
$().SpfileLenKb()

//Get Current File Url
$().SpgetUrl()

//Test if StreamPlug is Playing
$().SpisPlaying()

//Playlists
///////////

//Add an url in the playlist
$().SpaddUrl(url)

//Add pls to the Playlist
$().SpaddPl(url)

//Add An Url With Name
$().SpaddUrlName(url,title)

//Add Crypted Playlist
$().SpaddCryptedPl(url)

//Add Subtitle File/Url
$().SpaddSrt(file,title)

//Add Saveable url to playlist
$().SpaddSaveAblePl(url)

//Add .plc to the Playlist
$().SpaddCryptedPl2(url,key)

//Empty the Playlist
$().SpresetPl()

//Load specified skin
$().SploadSkin(url,Name)

//Move Playlist Window
$().SpmovePlWin(x,y)

//Pause Current Stream
$().Sppause()

//Play An Url
$().SpplayUrl(url)

//Play Item # in Playlist
$().SpplayPlItem()

//Play Current Stream
$().Spplay()

//Play and Save Url
$().SpplaySaveableUrl(url)

//Play Prev Item
$().Spprev()

//Play Next Item
$().Spnext()

//Start After n Kb
$().SpstartAfterKb(KB)

//Stop Current Stream
$().Spstop()

//Play Item From db
$().SpplayUrlFromDb(id)

//Play a cgi sec file
$().Spplaycgi2(url,fid,user,pass)

//Play a cgi file
$().SpplayCGi(url,id)

//Play Multiple (audio/video separated)
$().SpplayMutiple(VideoFile,AudioFile)

//Set Video Size
$().SpsetVideoSize(w,h)

//Set Original Size
$().SpsetVideoSizeOrig()

//Set Loop mode
$().SpsetLoop(state)

//Set BackGround Color
$().SpsetBKColor(R,G,B)

//Set Video Ratio
$().SpsetRatio(w,h)

//Set Volume
$().SpsetVolume(vol)

//Set Play-on-Start Attribute
$().SpplayOnStart(state)

//Set Full Screen
$().SpsetFullScreen(state)

//Set if user Can Resize
$().SpcanResize(state)

//Set if user Can Download
$().SpCanDownload(state)

//Set Border Size
$().SpsetBorderSize(size)

//Set Border Color
$().SpsetBorderColor(R,G,B)

//Set Active Srt (-1 none)
$().SpsetActiveSrt(id)

//Reset Srt
$().SpresetSrt()

//Set playmode
$().SpsetPlayMode(mode)

//Set Video Url
$().SpsetVideoUrl(url)

//Set Video Url Ms
$().SpsetVideoUrlMs(url,ms,endplay)

//Set Video Url Ms +ID
$().SpsetVideoUrlMsWithId()

//Set Event Grid Pos
$().SpsetEventGridPos(x,y,Id)

//Set Event Grid Size
$().SpsetEventGridSize(w,h)

//Set Event Js
$().SpsetEventJS(ID)

//Set pos kb
$().SpsetPositionKb(KB)

//Set pos ms
$().SpsetPositionMs(ms,endplay)

//Set color of A/V buffers
$().SpsetBufferColor(R,G,B)

//Windows
/////////

//Show Pluggle Version
$().SpshowVersion(state)

//Show the playlist window
$().SpshowPlaylist(state)

//Show Option Window
$().SpshowOption(state)

//Show Server Version
$().Spservversion()