Forums | developer.brewmp.com Forums | developer.brewmp.com

Developer

Forums

Forums:

IMedia - Simultaneous media playback

This section discusses how user can simultaneously play multiple media using the IMedia interface. This is called the multi-sequencer feature. The basic philosophy of creating and using the IMedia object still holds. To play multiple media simultaneously, an application creates an the IMedia object corresponding to each media. Each IMedia object is configured so that system resources are allocated to enable mixing of the audio from the media playback. This discussion covers the following broad steps.

     

  • Setting up media sources

  • Enabling channel share

  • Starting the playback

       - Using playback controls 

  • Handling error conditions encountered during these steps.

 

Note:

The device capabilities enforce certain restrictions on number and type of simultaneous media. For example, Qualcomm MSM-based devices can typically simultaneously play the following media sets:  

  • 1 MIDI / MMF / PMD(with MIDI) + 4 QCP(fixed) / AMR / ADPCM (all 4 of same type) [QCP needs to be started first before MIDI/PMD]

  • [Using 6550 and above] 4 MIDI / MMF / PMD(with MIDI) + 4 QCP(fixed) / AMR / ADPCM (all 4 of same type)

  • To start simultaneous playback of new media set, release all the IMedia objects in the current set

 

 

 

Step 1: Set the media source as file or buffer in the IMedia object

 

Take three ADPCM files that will be played simultaneously. The files are a1.wav, a2.wav and a3.wav. The corresponding IMedia objects created are called pIMedia1, pIMedia2 and pIMedia3.

{
      //
	// Setup the IMedia objects with media files
	//
	AEEMediaData	md;

	md.clsData = MMD_FILE_NAME;
	md.dwSize = 0;

	// a1.wav: Create IMedia object and set the media data
	if (SUCCESS != ISHELL_CreateInstance(pme->a.m_pIShell, AEECLSID_MEDIAADPCM, (void **)&pme->m_pIMedia1))
   {
      // Failed to create media object. Handle error condition.
      return;
   }
	md.pData = "a1.wav";
	if (SUCCESS != IMEDIA_SetMediaData(pme->m_pIMedia1, &md))
   {
      // Failed to set media data. Handle error condition.
      return;
   }
	// Register a callback notification function
	if (SUCCESS != IMEDIA_RegisterNotify(pme->m_pIMedia1, CApp_Media1Notify, pme))
   {
      // Failed to register callback. Handle error condition.
      return;
   }

	// a2.wav: Create IMedia object and set the media data
	ISHELL_CreateInstance(pme->a.m_pIShell, AEECLSID_MEDIAADPCM, (void **)&pme->m_pIMedia2);
   {
      // Failed to create media object. Handle error condition.
      return;
   }
	md.pData = "a2.wav";
	if (SUCCESS != IMEDIA_SetMediaData(pme->m_pIMedia2, &md))
   {
      // Failed to set media data. Handle error condition.
      return;
   }
	// Register a callback notification function
	if (SUCCESS != IMEDIA_RegisterNotify(pme->m_pIMedia2, CApp_Media2Notify, pme))
   {
      // Failed to register callback. Handle error condition.
      return;
   }

	// a3.wav: Create IMedia object and set the media data
	if (SUCCESS != ISHELL_CreateInstance(pme->a.m_pIShell, AEECLSID_MEDIAADPCM, (void **)&pme->m_pIMedia3))
   {
      // Failed to create media object. Handle error condition.
      return;
   }
	md.pData = "a3.wav";
	if (SUCCESS != IMEDIA_SetMediaData(pme->m_pIMedia3, &md))
   {
      // Failed to set media data. Handle error condition.
      return;
   }
	// Register a callback notification function
	if (SUCCESS != IMEDIA_RegisterNotify(pme->m_pIMedia3, CApp_Media3Notify, pme))
   {
      // Failed to register callback. Handle error condition.
      return;
   }

 

 After the IMedia objects are created, they will be in the IDLE state. IMEDIA_SetMediaData() is called in the IDLE state. After the successful execution of this API, the IMedia objects transition from the IDLE to READY state. Refer to the IMedia state machine diagram. When the user enables the channel share feature in IMedia, the IMedia object performs the necessary functions to allocate system multimedia resources. This allows simultaneous playback of the media.

 

 

Step 2: Enable the channel share feature for each IMedia object

IMEDIA_EnableChannelShare() allows an application to enable or disable this feature. For each media, enable this feature as follows:

	nErr = IMEDIA_EnableChannelShare(pme->pIMedia1, TRUE);
   if (SUCCESS != nErr)
   {
      // Handle error condition
      return;
   }
	nErr = IMEDIA_EnableChannelShare(pme->pIMedia2, TRUE);
   if (SUCCESS != nErr)
   {
      // Handle error condition
      return;
   }
	nErr = IMEDIA_EnableChannelShare(pme->pIMedia3, TRUE);
   if (SUCCESS != nErr)
   {
      // Handle error condition
      return;
   }

After the media source is set and the channel share feature is enabled for each IMedia object, the playback of the individual media needs to be started.

 

Step 3: Play the media simultaneously

For each media, call IMEDIA_Play().

	nErr = IMEDIA_Play(pme->pIMedia1);
   if (SUCCESS != nErr)
   {
      // Handle error condition
      return;
   }
	nErr = IMEDIA_Play(pme->pIMedia2);
   if (SUCCESS != nErr)
   {
      // Handle error condition
      return;
   }
	nErr = IMEDIA_Play(pme->pIMedia3);
   if (SUCCESS != nErr)
   {
      // Handle error condition
      return;
   }

 

Note:

If the device is MSM-based, the BREW version is 3.1.5 or lower and the media type is QCP/AMR/ADPCM, after step(a), an application must yield and then carryout steps (b) and (c). The best place to perform steps (b) and (c) is using the CApp_Media1Notify() function when the MM_STATUS_START arrives in response to step (a). This needs to be done only once. After that, as long as at least one of the IMedia objects is alive, you can synchronously call multiple IMEDIA_Play() as shown above. Typically, there should be no performance impact due to this change as MM_STATUS_START arrives in a few (<10) milliseconds.

{
	 //
	// Call the first play
	//
	nErr = IMEDIA_Play(pme->pIMedia1);
   if (SUCCESS != nErr)
   {
      // Handle error condition
      return;
   }

	// Yield now


static void CApp_Media1Notify(void * po, AEEMediaCmdNotify * pcn)
{
	CApp * pme = (CApp *)po;

	// Start received. Resources are setup.
	// Call the second and third play
	if (MM_STATUS_START == pcn->nStatus)
	{
	   nErr = IMEDIA_Play(pme->pIMedia2);
      if (SUCCESS != nErr)
      {
         // Handle error condition
         return;
      }
	   nErr = IMEDIA_Play(pme->pIMedia3);
      if (SUCCESS != nErr)
      {
         // Handle error condition
         return;
      }
	}

 

 

Step 4: Handle play events

Each IMedia object will start receiving the play events. The MM_STATUS_START is received to indicate that the playback is about to begin. The MM_STATUS_DONE is received when the playback ends. For a complete list of status, please see AEEMediaCmdNotify.

Using playback controls

You can invoke various playback control APIs like volume, pan, and so forth on each IMedia object in order to control that media’s playback.

 

Step 5a: Set the volume level

The individual media volume can be controlled by calling the IMEDIA_SetVolume() API on each IMedia object.

	// Set the volume level to the value set in pme->uVolume1
	nErr = IMEDIA_SetVolume(pme->pIMedia1, pme->uVolume1);
   if (SUCCESS != nErr)
   {
      // Handle error condition
      return;
   }

 

Step 5b: Set the pan factor

The individual media pan setting can be controlled by calling the IMEDIA_SetPan() API on each IMedia object.

	// Set the volume level to the value set in pme->uPan1
	nErr = IMEDIA_SetPan(pme->pIMedia1, pme->uPan1);
   if (SUCCESS != nErr)
   {
      // Handle error condition
      return;
   }

 

Step 6: Stop the playback

To stop the multi-sequence completely, call stop on each IMedia object:

	IMEDIA_Stop(pIMedia1);
	IMEDIA_Stop(pIMedia2);
	IMEDIA_Stop(pIMedia3);

 

Note: At this point, each IMedia object is still alive and the channel share feature is enabled. You can now simply restart the playback, by synchronously calling IMEDIA_Play() as shown in step #3 above. Following are common error conditions that an application may encounter.

     

  1. IMEDIA_SetMediaData() failed. A likely cause is setting a NULL buffer or a zero buffer size. In this case, the IMedia object will stay in the IDLE state. You can set the media source again.

  2. IMEDIA_Play() call failed. A likely cause is that the media is not in the READY state or the system resources are not available. Check the media state and availability of system resources like memory.

  3. Second IMEDIA_Play()call failed. If you are invoking multiple plays, after the first play is going on, then the system setting up multimedia resources for the second media fails. See Step 3: Play the media simultaneously which shows how you may want to yield after the first play.

  4. MM_STATUS_START did not arrive, instead MM_STATUS_ABORT happened. This means the device multimedia layer has aborted the play operation. Likely reasons include: an invalid or unsupported media format, an unavailability of multimedia resources, or an interruption by a high priority operation like a voice call or SMS.

  5. Playback stopped abruptly and MM_STATUS_ABORT happened. Same as #4 "MM_STATUS_START did not arrive" above.