sunnuntai 14. maaliskuuta 2010

The conclusion of the previous post was that we want to create a single application binary, which can use the latest features in the camera API, but also works on older devices. In this post, we'll look at instantiating CCamera in a way that allows this.

There are two different observer interfaces for CCamera. MCameraObserver is the older one and works on all devices – MCameraObserver2 provides more information and enables use of CCameraAdvancedSettings, but is only supported on S60 3rd edition FP2 and newer devices. The observer interface to be used is selected calling either CCamera::NewL and CCamera::New2L to instantiate CCamera. If the selected interface type (or use of camera in general) is not supported, the function will leave with KErrNotSupported.

The most obvious idea, that first comes to the mind after we have a class that implements both of the observer interfaces, is first calling New2L, and if it didn't work, falling back to NewL. The code might look something like this:

TRAPD(err, iCamera = CCamera::New2L(*this, KCameraIndex, KPriority));

if( KErrNone != err )
{
// MCameraObserver2 not available, use MCameraObserver
iCamera = CCamera::NewL(*this, KCameraIndex);
}

However, an application, which contains this piece of code, will not start on older devices - instead, the error note "Menu: Feature not supported (-5)" is displayed. It turns out that the function ordinal for New2L does not exist in ecam.dll on S60 3rd edition FP1 devices and earlier, and this causes application loading to fail.

As calling New2L function normally causes problems, we'll have to load the ECam DLL dynamically, resolve the function by its ordinal, and then call it through the resulting function pointer. If any of these steps fails, we know that the MCameraObserver2 interface is not supported. The code to do this can be written as follows:

// New2L is the 17th exported function in ecam.dll (see ecam.lib)
_LIT(KECamDll, "ecam.dll");
const TInt KNew2LOrdinal = 17;

// New2L returns CCamera ptr, params are MCameraObserver2 reference and 2 TInts
typedef CCamera*(* New2LFunction)(MCameraObserver2&, TInt, TInt);

void CCameraHandler::TryNew2L(MCameraObserver2& aObserver,TInt aCameraIndex,TInt aPriority)
{
RLibrary ecamLib;
CleanupClosePushL(ecamLib);

// Load library, lookup function
User::LeaveIfError(ecamLib.Load(KECamDll));
New2LFunction CCamera_New2L((New2LFunction)ecamLib.Lookup(KNew2LOrdinal));

if( NULL == CCamera_New2L )
{
// Function not available in DLL
User::Leave(KErrNotSupported);
}

// Call CCamera::New2L
iCamera = CCamera_New2L(aObserver, aCameraIndex, aPriority);

CleanupStack::PopAndDestroy(); // ecamLib
}


New2L is then replaced with a call to this function. The final instantiation code:

TRAPD(err, TryNew2L(*this, KCameraIndex, KPriority));

if( KErrNone != err )
{
// MCameraObserver2 not available, use MCameraObserver
iCamera = CCamera::NewL(*this, KCameraIndex);
}

MCameraObserver2 is now used where it's available, MCameraObserver is used on older devices, and the same application binary can be launched on any S60 3rd or 5th edition device. Next post will take a look at using CCameraAdvancedSettings via dynamic DLL loading and a wrapper class.

1 kommentti:

Lukijat