2010年8月4日 星期三

USB Audio Class Driver 開發

在開發的過程中, USBDeviceAttach 被呼叫了四次(第三個參數usb interface 都不相同,因為總共有4個 interface,USBAudio算是 interface driver,所以第一個interface 載入成功的話會載入下個interface。詳情請看 LoadDeviceDrivers() in usbd.cpp。
雖然被載入4次,但不會重複載入DLL (也就是DLLMain PROCESS_ATTACH 只會CALL 一次,之後的應該是THREAD_ATTACH)。
如果你的USB Client Driver 不是 interface driver 的話,則USBDeviceAttach第三個參數為 NULL。
還有 LoadDeviceDrivers 的載入interface driver 部份有點問題,它總共會載入 bNumInterfaces 次, 這個bNumInterfaces 是 active configuration 的 descriptor (USB_CONFIGURATION_DESCRIPTOR) 但 interface++ 的部份有點不對,因為每個interface又有可能有alternate setting ,所以總共的interface (含alternate setting) 應該是 dwNumInterfaces 個 ( USB_CONFIGURATION ) 。這一點我發現在 WINCE 6 usbd.cpp中改了過來,有把alternate setting 的狀況考慮進去。



USB Audio Output procedure

1. Set Interface  ( Interface 1, Alternate Setting 1 )
2. GetEndpoint
3. OpenPipe
4. IssueIsochTransfer

而 USB Mic Recording 基本上跟 Audio Out 一樣,不過怎麼試
都得不到正確資料,而是抓到整個 Configuration Descriptor

想破腦袋後,並從Bus Hound,發現Set Interface 後有 SET_CUR
而這個SET_CUR 就是設定 Audio In Endpoint 的 frequency,果然再 issue 這個
SET_CUR 的 VendorTransfer 後就可以正常讀取 Audio Stream 了。(請參考 Audio Class spec
第五章 request ),當然 bits 數 ,frequency, channel 都要正確才行。


USB Audio Input procedure

1. Set Interface  ( Interface 2, Alternate Setting 2 )
2. GetEndpoint
3. Send Endpoint Frequency Request
4. OpenPipe
5. IssueIsochTransfer


Note: 在 IssueIsochTransfer 的 callback function 中呼叫 closepipe的話,
會再多出一次 callback

Note!! 在 IssueIsochTransfer 的 callback function 中呼叫 WriteFile,而這個檔案又位在
USB Disk上時,這個WriteFile 會block住。所以,要再Create專門WriteFile 的Thread
不能在 callback中 WriteFile

如果要做 Isoch Transfer 這篇文章很重要
http://support.microsoft.com/?scid=kb;en-us;317434&x=14&y=7

DRVM_MAPPER_PREFERRED_SET 
設定 default waveout device
http://msdn.microsoft.com/en-us/library/dd187525.aspx
http://msdn.microsoft.com/en-us/library/aa908376.aspx
http://relatedterms.com/thread/2314671/Multiple%20Audio%20Devices%20Win%20CE



MMRESULT Err = waveOutMessage((HWAVEOUT)WAVE_MAPPER,
DRVM_MAPPER_PREFERRED_SET,
CurDeviceID,
0
);

    把指定的 audio driver id 設成 0 (也就是 default audio driver )



MMRESULT Err = waveOutMessage((HWAVEOUT)WAVE_MAPPER,
DRVM_MAPPER_PREFERRED_SET,
CurDeviceID,
(DWORD)-1
); 

 把指定的 audio driver id 設成-1 (變成最後一個,比如說總共有3個driver, 0 1 2 那就會變成 2 )




USB Audio Class Driver 除了 USB 的部份還有Audio Driver的部份
之後有2個 audio device,所以才會想到用 DRVM_MAPPER_PREFERRED_SET 來設定 default audio device。DRVM_MAPPER_PREFERRED_SET 在 WINCE 5 NavReady 2009 ( ARM Only )和在 WINCE 6 R3之後才有支援。不支援的話呼叫會傳回 8 (MMSYSERR_NOTSUPPORTED)




除了不支援設定哪個default 之外,要load 2 個 audio driver 也遇到了問題
http://www.pocketpcjunkies.com/Uwe/Forum.aspx/wince-pb/10473/how-to-install-the-second-audio-driver
 search   "load audio driver wince"






但是看了WINCE 5 的help 之後,發現Audio Driver 有兩種,一種是 MDD+PDD 另一種是 UAM
(Unified Driver Model )。
可惜的是,MDD+PDD 只support only one device ( waveOutGetNumDevs always returns 1 )
新發現第三種 wavedev2 audio model ( Sample available in WINCE 6 ) (or WINCE 5 NMD Pack )
http://msdn.microsoft.com/en-us/library/ee485233.aspx
wavedev2 好像有support S/PDIF
http://www.ms-news.net/f3868/question-about-audio-driver-wince5-0-a-11725972.html

google wavedev2 waveapi.dll
http://news.rdeasy.cn/yingyong/20100208/7921.html


Writing a Network Audio Driver in WINCE
http://blogs.msdn.com/b/cenet/archive/2005/10/10/479282.aspx

Audio MDD PDD
在使用 MDD (wavemdd.lib) 的時候,PDD 部份要定義 gIntrAudio,並InterruptConnect 此 gIntrAudio。


Audio Stack 架構圖 ( described in wavedev.h )


//  @topic  Wave Audio API Manager Device Interface |
//          The COREDLL.DLL Dynamic Link Library gives user applications
//          access to the Waveform Audio functions.
//
//          The Waveform Audio API Manager exports the waveXXX functions via the
//          device manager's IOCTL calls. IOCTL_XXX constants are defined in
//          wavedev.h.
//
//  @ex     Software Layers |
//  
// *       ===============    ===============
// *       | Application |    | Application |  Module(s)
// *       ===============    ===============
// *    
// *         --------- MMSYSTEM.H ---------    Interface
// *    
// *       ==================================
// *       |          COREDLL.DLL           |  Module  (coredll.dll)
// *       ==================================
// *    
// *         ---------- WAVEDEV.H ---------    Interface
// *    
// *         ------ DeviceIoControl() -----    PSL API
// *    
// *       ==================================
// *       |     WAPI (Wave API Manager)    |  Module (waveapi.dll)
// *       ==================================
// *    
// *         ---------- WAVEDEV.H ---------    Interface
// *    
// *         ------ DeviceIoControl() -----    PSL API
// *    
// *       ==================================
// *       |            WAVEMDD             |  Module (wavedev.dll)
// *       ==================================
// *    
// *         --------- WAVEDDSI.H ---------    Interface
// *    
// *       ==================================
// *       |            WAVEPDD             |  Module (wavedev.dll)
// *       ==================================





DRVM_MAPPER_PREFERRED_SET and DRVM_MAPPER_PREFERRED_GET are not defined by Windows Embedded CE. To use these messages, you must first define them in your code, as follows:


#define DRVM_MAPPER 0x2000
#define DRVM_MAPPER_PREFERRED_GET (DRVM_MAPPER+21) 
#define DRVM_MAPPER_PREFERRED_SET (DRVM_MAPPER+22)