Create a File with 2 Audio Streams that are Mutually Exclusive

The following code can be used to create a file with two audio streams that are mutually exclusive:

BSTR bstr;
CString fname; 
HRESULT hr; 
USES_CONVERSION; 

if( m_pConvert == NULL ) 
   return; 

// Create the profile manager object: 
hr = CoCreateInstance(CLSID_ltmmWMProfileManager, NULL, CLSCTX_INPROC_SERVER, IID_IltmmWMProfileManager, (void**) &m_pProfMan); 

// create an empty profile: 
hr = m_pProfMan->CreateEmptyProfile (ltmmWMT_VER_7_0, &m_pProf); 

// Set the profile name and description
hr = m_pProf->put_Name (L"Mutex Stream_test");
hr = m_pProf->put_Description (L"Example code");

// add 2 audio streams with different bitrates
hr = AddAudioStream(mgr, profile, 1, CODEC_AUDIO_MSAUDIO, 8000, 8000, 1, FALSE); 
hr = AddAudioStream(mgr, profile, 2, CODEC_AUDIO_MSAUDIO, 16000, 16000, 1, FALSE); 

// make them mutually exclusive
hr = AddMutexObject(profile, 1, 2); 

// add the profile to the convert object
hr = m_pConvert->put_WMProfile (m_pProf); 
m_pProf->Release();
m_pProfMan->Release();

//set the target format 
hr = m_pConvert->put_TargetFormat (  ltmmConvert_TargetFormat_Asf_Compressor_Mux ); 

// set the source file name; the source file contains multiple audio streams: 
hr = m_pConvert->put_SourceFile (L"London.avi");

// set the output file name: 
hr = m_pConvert->put_TargetFile ("London.asf");

// do the conversion
hr = m_pConvert->StartConvert ();

HRESULT AddVideoStream( IltmmWMProfileManager* mgr, 
                IltmmWMProfile* profile, 
                UINT nStreamNum, 
                DWORD dwFourCC, 
                ULONG nBitRate, 
                ULONG nWidth, 
                ULONG nHeight, 
                ULONG nFPS, 
                ULONG nQuality, 
                ULONG nSecPerKey ) 
{
   long cCodecs; 
   IltmmWMStreamConfig* stream = NULL; 
   IltmmMediaTypeDisp* pmt = NULL; 
   VIDEOINFOHEADER *pVIH = NULL; 
   VARIANT varFormat; 
   VariantInit(&varFormat); 
   
   // get MEDIATYPE_Video codec count
   BSTR bstr = ::SysAllocString(ltmmMEDIATYPE_Video); 
   HRESULT hr = mgr->GetCodecInfoCount(bstr, &cCodecs); 
   ::SysFreeString(bstr); 

   // search for matching codec
   for(long i = 0; !stream && i < cCodecs; i++)
   {
      long cFormats; 
      // get MEDIATYPE_Video codec format count
      BSTR bstr = ::SysAllocString(ltmmMEDIATYPE_Video); 
      HRESULT hr = mgr->GetCodecFormatCount(bstr, i, &cFormats); 
      ::SysFreeString(bstr); 

      for(long j = 0; j < cFormats; j++)
      {
         // get MEDIATYPE_Video stream config interface
         bstr = ::SysAllocString(ltmmMEDIATYPE_Video); 
         hr = mgr->GetCodecFormat(bstr, i, j, &stream); 
         ::SysFreeString(bstr); 
         if(SUCCEEDED(hr)) 
         {
            // get this format's media type
            hr = stream->GetMediaType (&pmt); 
            if(SUCCEEDED(hr)) 
            {
               hr = pmt->get_FormatType(&bstr); 
               if(SUCCEEDED(hr)) 
               {
                  // only check FORMAT_VideoInfo formats
                  if(!wcsicmp(bstr, ltmmFORMAT_VideoInfo)) 
                  {
                     pmt->GetFormatData(-1, &varFormat); 
                     SafeArrayAccessData(V_ARRAY(&varFormat), (void**) &pVIH); 
                     if(pVIH->bmiHeader.biCompression == dwFourCC) 
                     {
                        ::SysFreeString(bstr); 
                        break; 
                     }
                     SafeArrayUnaccessData(V_ARRAY(&varFormat)); 
                     VariantClear(&varFormat); 
                  }
                  ::SysFreeString(bstr); 
               }
               pmt->Release();
               pmt = NULL; 
            }
            stream->Release();
            stream = NULL; 
         }   
         
      }
      
   }
   // return an error, if we didn't find a good candidate
   if(!stream) 
      return E_FAIL; 
   
   pVIH->dwBitRate = nBitRate; 
   
   pVIH->rcSource.right = nWidth; 
   pVIH->rcSource.bottom = nHeight; 
   pVIH->rcTarget.right = nWidth; 
   pVIH->rcTarget.bottom = nHeight; 
   pVIH->bmiHeader.biWidth = nWidth; 
   pVIH->bmiHeader.biHeight = nHeight; 
   
   pVIH->AvgTimePerFrame = ((LONGLONG) 10000000 ) / ((LONGLONG) nFPS ); 
   
   pmt->SetFormatData(-1, varFormat); 

   hr = stream->put_Quality ( nQuality ); 
   
   hr = stream->put_MaxKeyFrameSpacing ((double) nSecPerKey); 
   
   
   stream->put_StreamNumber (nStreamNum); 

   bstr = ::SysAllocString(L"Video Stream");
   stream->put_StreamName (bstr); 
   ::SysFreeString(bstr); 

   bstr = ::SysAllocString(L"Video");
   stream->put_ConnectionName(bstr); 
   ::SysFreeString(bstr); 

   stream->put_Bitrate(nBitRate); 

   stream->SetMediaType (pmt); 

   profile->AddStream (stream); 

   stream->Release();
   pmt->Release();
   SafeArrayUnaccessData(V_ARRAY(&varFormat)); 
   VariantClear(&varFormat); 

   return S_OK; 
}

HRESULT AddAudioStream(IltmmWMProfileManager* mgr, 
                                  IltmmWMProfile* profile, 
                                  UINT nStreamNum, 
                                  UINT nFormatTag, 
                                  ULONG nBitRate, 
                                  ULONG nSamplesPerSec, 
                                  UINT nChannels, 
                                  BOOL bVideo) 
{
   long cCodecs; 
   
   VARIANT varSave; 
   VariantInit(&varSave); 
   
   // get MEDIATYPE_Audio codec count
   BSTR bstr = ::SysAllocString(ltmmMEDIATYPE_Audio); 
   HRESULT hr = mgr->GetCodecInfoCount (bstr, &cCodecs); 
   ::SysFreeString(bstr); 
   
   // search for matching codec
   for(long i = 0; i < cCodecs; i++)
   {
      long cFormats; 
      // get MEDIATYPE_Audio codec format count
      BSTR bstr = ::SysAllocString(ltmmMEDIATYPE_Audio); 
      HRESULT hr = mgr->GetCodecFormatCount (bstr, i, &cFormats); 
      ::SysFreeString(bstr); 

      for(long j = 0; j < cFormats; j++)
      {
         // get MEDIATYPE_Audio stream config interface
         IltmmWMStreamConfig* format; 
         bstr = ::SysAllocString(ltmmMEDIATYPE_Audio); 
         hr = mgr->GetCodecFormat (bstr, i, j, &format); 
         ::SysFreeString(bstr); 
         if(SUCCEEDED(hr)) 
         {
            // get this format's media type
            IltmmMediaTypeDisp* pmt; 
            hr = format->GetMediaType (&pmt); 
            if(SUCCEEDED(hr)) 
            {
               hr = pmt->get_FormatType(&bstr); 
               if(SUCCEEDED(hr)) 
               {
                  // only check FORMAT_WaveFormatEx formats
                  if(!wcsicmp(bstr, ltmmFORMAT_WaveFormatEx)) 
                  {
                     VARIANT var; 
                     VariantInit(&var); 
                     pmt->get_Format(&var); 
                     WAVEFORMATEX *pWfx; 
                     SafeArrayAccessData(V_ARRAY(&var), (void**) &pWfx); 
                     
                     // does this format look like a good candidate
                     long nDiff = (long) (pWfx->nAvgBytesPerSec * 8 - nBitRate); 
                     if( nDiff < 250 &&
                        nDiff > -250 &&
                        pWfx->nSamplesPerSec == nSamplesPerSec &&
                        pWfx->nChannels == nChannels &&
                        pWfx->wFormatTag == nFormatTag) 
                     {
                        
                        if( V_VT(&varSave) != VT_EMPTY ) 
                        {
                           WAVEFORMATEX *pSaveWFX; 
                           SafeArrayAccessData(V_ARRAY(&varSave), (void**) &pSaveWFX); 
                           if(bVideo) 
                           {
                              //
                              // For audio/video configurations, we want to
                              // find the smaller nBlockAlign. In this case, 
                              // the nBlockAlign is larger, so we want to
                              // use the old format. 
                              //
                              if( pWfx->nBlockAlign <= pSaveWFX->nBlockAlign ) 
                              {
                                 SafeArrayUnaccessData(V_ARRAY(&varSave)); 
                                 VariantClear(&varSave); 
                                 VariantCopy(&varSave, &var); 
                              }
                           }
                           else
                           {
                              // otherwise, we want the larger nBlockAlign
                              if( pWfx->nBlockAlign >= pSaveWFX->nBlockAlign ) 
                              {
                                 SafeArrayUnaccessData(V_ARRAY(&varSave)); 
                                 VariantClear(&varSave); 
                                 VariantCopy(&varSave, &var); 
                              }
                           }
                           
                        }
                        else
                        {
                           VariantClear(&varSave); 
                           VariantCopy(&varSave, &var); 
                        }
                     }
                     SafeArrayUnaccessData(V_ARRAY(&var)); 
                     VariantClear(&var); 
                  }
                  ::SysFreeString(bstr); 
               }
               
               pmt->Release();
            }
            
            format->Release();
         }   
         
      }
      
   }
   // return an error, if we didn't find a good candidate
   if( V_VT(&varSave) == VT_EMPTY) 
      return E_FAIL; 
   
   WAVEFORMATEX *pSaveWFX; 
   SafeArrayAccessData(V_ARRAY(&varSave), (void**) &pSaveWFX); 
   IltmmMediaTypeDisp* pmt; 
   
   hr = CoCreateInstance(CLSID_ltmmMediaType, NULL, CLSCTX_INPROC_SERVER, IID_IltmmMediaTypeDisp, (void**) &pmt); 
   
   // setup the new stream's media type
   bstr = ::SysAllocString(ltmmMEDIATYPE_Audio); 
   pmt->put_Type(bstr); 
   ::SysFreeString(bstr); 
   
   CString s; 
   s.Format(_T("{%.8X-0000-0010-8000-00AA00389B71}"), (UINT) pSaveWFX->wFormatTag); 
   bstr = s.AllocSysString();
   pmt->put_Subtype(bstr); 
   ::SysFreeString(bstr); 
   
   pmt->put_FixedSizeSamples(VARIANT_TRUE); 
   pmt->put_TemporalCompression(VARIANT_FALSE); 
   pmt->put_SampleSize(pSaveWFX->nBlockAlign); 
   
   bstr = ::SysAllocString(ltmmFORMAT_WaveFormatEx); 
   pmt->put_FormatType(bstr); 
   ::SysFreeString(bstr); 
   
   pmt->SetFormatData(-1L, varSave); 
   
   IltmmWMStreamConfig* stream; 
   bstr = ::SysAllocString(ltmmMEDIATYPE_Audio); 
   hr = profile->CreateNewStream (bstr, &stream); 
   ::SysFreeString(bstr); 
   
   stream->put_StreamNumber (nStreamNum); 
   
   bstr = ::SysAllocString(L"Audio Stream");
   stream->put_StreamName (bstr); 
   ::SysFreeString(bstr); 
   
   bstr = ::SysAllocString(L"Audio");
   stream->put_ConnectionName(bstr); 
   ::SysFreeString(bstr); 
   
   stream->put_Bitrate(pSaveWFX->nAvgBytesPerSec * 8); 
   
   hr = stream->SetMediaType (pmt); 
   
   hr = profile->AddStream (stream); 

   stream->Release();
   pmt->Release();
   SafeArrayUnaccessData(V_ARRAY(&varSave)); 
   VariantClear(&varSave); 
   
   return S_OK; 
}

HRESULT AddMutexObject(IltmmWMProfile *profile, UINT nBaseStream, UINT nStreamCount) 
{
    IltmmWMMutualExclusion *excl = NULL; 

   // create an exclusion object
   HRESULT hr = profile->CreateNewMutualExclusion (&excl); 

   // mark all the streams for mutual exclusion
   for(UINT i = 0; i < nStreamCount; i++)
   {
      hr = excl->AddStream (nBaseStream + i); 
   }

   // indicate that the streams differ by Bitrate
   // see CLSID_WMMUTEX_Bitrate in the WMSDK
   BSTR bstr = ::SysAllocString(L"{D6E22A01-35DA-11D1-9034-00A0C90349BE}");
   hr = excl->put_Type(bstr); 
   ::SysFreeString(bstr); 

   // assign the exclusion object to the profile
   hr = profile->AddMutualExclusion (excl); 
   excl->Release();
   return hr; 
}