free web page counters

Windows Mobile Pocket PC Smartphone Programming

==>Click here for the SiteMap<==. Original contents with decent amount of source codes.

Thursday, May 11, 2006

Pocket PC Power Management Series 11: Play sound (for example, wav file) when a Pocket PC is suspended

====>SiteMap of this Blog<===

Pocket PC Power Management Series 11: Play sound (for example, wav file) when a Pocket PC is suspended

I am going to write a new series on Pocket PC Power Management topic: How to play sound when Pocket PC is sleeping or suspended. Let me use a simple API to achieve this purpose: PlaySound.

Why care?

If you read my previous series on the Power Management topic, you may ask why we care. If the Pocket PC sleeps, no thread can run, so PlaySound won't even be called. If the PPC is not sleeping, PlaySound is called, so why the hassle? The answer is: Yes, PlaySound will be called, but you may not hear the sound! So the title of this blog is sort of misleading. It should be changed to something like "How to make sure there is a sound when the device is suspended".

Let us say, you write the code to request the PPC to play a wav file, even when it is suspended. A good example is the Alarm program. It might need to play a warning or ringtone at 8PM. This piece of code can be executed at 8PM, guaranteed by Windows CE OS. However, you may be disappointed not hearing any sound. Below I will explain why and how to solve the problem.

Why no Sound?

Ultimately a peripheral device needs to emit the sound. This peripheral must be powered or put into certain state so as to vibrate to produce sound waves. A good chance is: When PlaySound() is called, the Pocket PC is in such a "System Power State" that the sound peripheral is not supposed to work; or in Microsoft terms, the sound peripheral is in such a "Device Power State" mapped from the current "System Power State", that the sound peripheral might have no power, have low power or in standby mode.

For our specific alarm example, the Pocket PC might be in a "System Power State" called "Unattended". The sound peripheral is called "wav1:", which is put into a "D4 Device Power State", mapped from "Unattended" state. "D4" means "No Power", so you won't be able to hear any sound.

To above explanation might be too abstract. If you really need to understand those terms, please read Microsoft Platform Builder documentation on "Power Management".

A Possible Solution

A possible solution to the problem is to change the mapping, so as to change the power state of "wav1:" device. The following code snippet is doing this job:

HRESULT ChangeWav1Mapping()
{
   LRESULT lr = E_FAIL;

   HKEY hKey = NULL;
   DWORD dwSubKeys = 0;
   DWORD dwMaxSubkeyLen = 0;
   TCHAR szSubkeyName[MAX_PATH];

   lr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("\\System\\CurrentControlSet\\Control\\Power\\State"), 0, 0, &hKey);
   if (ERROR_SUCCESS != lr) goto FuncExit;

   lr = RegQueryInfoKey(hKey, NULL, 0, 0, &dwSubKeys, &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
   if (ERROR_SUCCESS != lr) goto FuncExit;

   for (int i=0; i<dwSubKeys; i++) {
      DWORD dwSubkeyNameLen = MAX_PATH-1;
      memset(szSubkeyName, 0, MAX_PATH*sizeof(TCHAR));
      lr = RegEnumKeyEx(hKey, i, szSubkeyName, &dwSubkeyNameLen, NULL, NULL, NULL, NULL);
      if (ERROR_SUCCESS != lr) continue;
      
      //ALERT(szSubkeyName);

      HKEY hSubkey = NULL;
      lr = RegOpenKeyEx(hKey, szSubkeyName, 0, 0, &hSubkey);
      if (ERROR_SUCCESS != lr) continue;

      // any wav1: ?
      DWORD dwValueType = 0;
      DWORD dwValueData = 0;
      DWORD dwValueDataLen = sizeof(DWORD);
      lr = RegQueryValueEx(hSubkey, TEXT("wav1:"), NULL, &dwValueType, (LPBYTE)&dwValueData, &dwValueDataLen);
      if (ERROR_SUCCESS == lr && 0 != dwValueData) {
         dwValueData = 0;
         RegSetValueEx(hSubkey, TEXT("wav1:"), NULL, REG_DWORD, (LPBYTE)&dwValueData, sizeof(DWORD));
      }
      RegCloseKey(hSubkey);
   }

   RegFlushKey(hKey);

FuncExit:
   if (hKey) {
      RegCloseKey(hKey);
   }

   return S_OK;
}

Notice this is a piece of bad code. It forces the "wav1:" device to be always powered, no matter what state the Pocket PC is in. Looks like that is the case for most Pocket PC 2003 devices, but probably not true for Pocket PC 5.0 device. So the above code effectively changes the sound behavior of PPC 5.0 device.

The recommended API to use to SetPowerRequirement and ReleasePowerRequirement. I will talk about them in a later post.

Wrap Up

Pocket PC sleeps. Read the following two posts for basis:

There are ways to force the device not to sleep, or request it to run a program at certain time or upon certain event:

The above techniques force the CPU to run, but not necessarily other peripheral devices. In this post we talked about "wav1:" and a possible hacky way to override the power mapping.

====>SiteMap of this Blog<===