pa_win_wmme.c 151 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015
  1. #ifdef _WIN32
  2. /*
  3. * $Id: pa_win_wmme.c 1874 2012-10-31 06:20:59Z rbencina $
  4. * pa_win_wmme.c
  5. * Implementation of PortAudio for Windows MultiMedia Extensions (WMME)
  6. *
  7. * PortAudio Portable Real-Time Audio Library
  8. * Latest Version at: http://www.portaudio.com
  9. *
  10. * Authors: Ross Bencina and Phil Burk
  11. * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
  12. *
  13. * Permission is hereby granted, free of charge, to any person obtaining
  14. * a copy of this software and associated documentation files
  15. * (the "Software"), to deal in the Software without restriction,
  16. * including without limitation the rights to use, copy, modify, merge,
  17. * publish, distribute, sublicense, and/or sell copies of the Software,
  18. * and to permit persons to whom the Software is furnished to do so,
  19. * subject to the following conditions:
  20. *
  21. * The above copyright notice and this permission notice shall be
  22. * included in all copies or substantial portions of the Software.
  23. *
  24. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  25. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  26. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  27. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
  28. * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
  29. * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  30. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  31. */
  32. /*
  33. * The text above constitutes the entire PortAudio license; however,
  34. * the PortAudio community also makes the following non-binding requests:
  35. *
  36. * Any person wishing to distribute modifications to the Software is
  37. * requested to send the modifications to the original developer so that
  38. * they can be incorporated into the canonical version. It is also
  39. * requested that these non-binding requests be included along with the
  40. * license above.
  41. */
  42. /* Modification History:
  43. PLB = Phil Burk
  44. JM = Julien Maillard
  45. RDB = Ross Bencina
  46. PLB20010402 - sDevicePtrs now allocates based on sizeof(pointer)
  47. PLB20010413 - check for excessive numbers of channels
  48. PLB20010422 - apply Mike Berry's changes for CodeWarrior on PC
  49. including conditional inclusion of memory.h,
  50. and explicit typecasting on memory allocation
  51. PLB20010802 - use GlobalAlloc for sDevicesPtr instead of PaHost_AllocFastMemory
  52. PLB20010816 - pass process instead of thread to SetPriorityClass()
  53. PLB20010927 - use number of frames instead of real-time for CPULoad calculation.
  54. JM20020118 - prevent hung thread when buffers underflow.
  55. PLB20020321 - detect Win XP versus NT, 9x; fix DBUG typo; removed init of CurrentCount
  56. RDB20020411 - various renaming cleanups, factored streamData alloc and cpu usage init
  57. RDB20020417 - stopped counting WAVE_MAPPER when there were no real devices
  58. refactoring, renaming and fixed a few edge case bugs
  59. RDB20020531 - converted to V19 framework
  60. ** NOTE maintanance history is now stored in CVS **
  61. */
  62. /** @file
  63. @ingroup hostapi_src
  64. @brief Win32 host API implementation for the Windows MultiMedia Extensions (WMME) audio API.
  65. */
  66. /*
  67. How it works:
  68. For both callback and blocking read/write streams we open the MME devices
  69. in CALLBACK_EVENT mode. In this mode, MME signals an Event object whenever
  70. it has finished with a buffer (either filled it for input, or played it
  71. for output). Where necessary, we block waiting for Event objects using
  72. WaitMultipleObjects().
  73. When implementing a PA callback stream, we set up a high priority thread
  74. which waits on the MME buffer Events and drains/fills the buffers when
  75. they are ready.
  76. When implementing a PA blocking read/write stream, we simply wait on these
  77. Events (when necessary) inside the ReadStream() and WriteStream() functions.
  78. */
  79. #include <stdio.h>
  80. #include <stdlib.h>
  81. #include <math.h>
  82. #include <windows.h>
  83. #include <mmsystem.h>
  84. #ifndef UNDER_CE
  85. #include <process.h>
  86. #endif
  87. #include <assert.h>
  88. /* PLB20010422 - "memory.h" doesn't work on CodeWarrior for PC. Thanks Mike Berry for the mod. */
  89. #ifndef __MWERKS__
  90. #include <malloc.h>
  91. #include <memory.h>
  92. #endif /* __MWERKS__ */
  93. #include "portaudio.h"
  94. #include "pa_trace.h"
  95. #include "pa_util.h"
  96. #include "pa_allocation.h"
  97. #include "pa_hostapi.h"
  98. #include "pa_stream.h"
  99. #include "pa_cpuload.h"
  100. #include "pa_process.h"
  101. #include "pa_debugprint.h"
  102. #include "pa_win_wmme.h"
  103. #include "pa_win_waveformat.h"
  104. #ifdef PAWIN_USE_WDMKS_DEVICE_INFO
  105. #include "pa_win_wdmks_utils.h"
  106. #ifndef DRV_QUERYDEVICEINTERFACE
  107. #define DRV_QUERYDEVICEINTERFACE (DRV_RESERVED + 12)
  108. #endif
  109. #ifndef DRV_QUERYDEVICEINTERFACESIZE
  110. #define DRV_QUERYDEVICEINTERFACESIZE (DRV_RESERVED + 13)
  111. #endif
  112. #endif /* PAWIN_USE_WDMKS_DEVICE_INFO */
  113. /* use CreateThread for CYGWIN, _beginthreadex for all others */
  114. #if !defined(__CYGWIN__) && !defined(_WIN32_WCE)
  115. #define CREATE_THREAD (HANDLE)_beginthreadex( 0, 0, ProcessingThreadProc, stream, 0, &stream->processingThreadId )
  116. #define PA_THREAD_FUNC static unsigned WINAPI
  117. #define PA_THREAD_ID unsigned
  118. #else
  119. #define CREATE_THREAD CreateThread( 0, 0, ProcessingThreadProc, stream, 0, &stream->processingThreadId )
  120. #define PA_THREAD_FUNC static DWORD WINAPI
  121. #define PA_THREAD_ID DWORD
  122. #endif
  123. #if (defined(_WIN32_WCE))
  124. #pragma comment(lib, "Coredll.lib")
  125. #elif (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) /* MSC version 6 and above */
  126. #pragma comment(lib, "winmm.lib")
  127. #endif
  128. /*
  129. provided in newer platform sdks
  130. */
  131. #ifndef DWORD_PTR
  132. #if defined(_WIN64)
  133. #define DWORD_PTR unsigned __int64
  134. #else
  135. #define DWORD_PTR unsigned long
  136. #endif
  137. #endif
  138. /************************************************* Constants ********/
  139. #define PA_MME_USE_HIGH_DEFAULT_LATENCY_ (0) /* For debugging glitches. */
  140. #if PA_MME_USE_HIGH_DEFAULT_LATENCY_
  141. #define PA_MME_WIN_9X_DEFAULT_LATENCY_ (0.4)
  142. #define PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_ (4)
  143. #define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_ (4)
  144. #define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_HALF_DUPLEX_ (4)
  145. #define PA_MME_HOST_BUFFER_GRANULARITY_FRAMES_WHEN_UNSPECIFIED_ (16)
  146. #define PA_MME_MAX_HOST_BUFFER_SECS_ (0.3) /* Do not exceed unless user buffer exceeds */
  147. #define PA_MME_MAX_HOST_BUFFER_BYTES_ (32 * 1024) /* Has precedence over PA_MME_MAX_HOST_BUFFER_SECS_, some drivers are known to crash with buffer sizes > 32k */
  148. #else
  149. #define PA_MME_WIN_9X_DEFAULT_LATENCY_ (0.2)
  150. #define PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_ (2)
  151. #define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_ (3) /* always use at least 3 input buffers for full duplex */
  152. #define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_HALF_DUPLEX_ (2)
  153. #define PA_MME_HOST_BUFFER_GRANULARITY_FRAMES_WHEN_UNSPECIFIED_ (16)
  154. #define PA_MME_MAX_HOST_BUFFER_SECS_ (0.1) /* Do not exceed unless user buffer exceeds */
  155. #define PA_MME_MAX_HOST_BUFFER_BYTES_ (32 * 1024) /* Has precedence over PA_MME_MAX_HOST_BUFFER_SECS_, some drivers are known to crash with buffer sizes > 32k */
  156. #endif
  157. /* Use higher latency for NT because it is even worse at real-time
  158. operation than Win9x.
  159. */
  160. #define PA_MME_WIN_NT_DEFAULT_LATENCY_ (0.4)
  161. /* Default low latency for WDM based systems. This is based on a rough
  162. survey of workable latency settings using patest_wmme_find_best_latency_params.c.
  163. See pdf attached to ticket 185 for a graph of the survey results:
  164. http://www.portaudio.com/trac/ticket/185
  165. Workable latencies varied between 40ms and ~80ms on different systems (different
  166. combinations of hardware, 32 and 64 bit, WinXP, Vista and Win7. We didn't
  167. get enough Vista results to know if Vista has systemically worse latency.
  168. For now we choose a safe value across all Windows versions here.
  169. */
  170. #define PA_MME_WIN_WDM_DEFAULT_LATENCY_ (0.090)
  171. /* When client suggestedLatency could result in many host buffers, we aim to have around 8,
  172. based off Windows documentation that suggests that the kmixer uses 8 buffers. This choice
  173. is somewhat arbitrary here, since we havn't observed significant stability degredation
  174. with using either more, or less buffers.
  175. */
  176. #define PA_MME_TARGET_HOST_BUFFER_COUNT_ 8
  177. #define PA_MME_MIN_TIMEOUT_MSEC_ (1000)
  178. static const char constInputMapperSuffix_[] = " - Input";
  179. static const char constOutputMapperSuffix_[] = " - Output";
  180. /*
  181. copies TCHAR string to explicit char string
  182. */
  183. char *StrTCpyToC(char *to, const TCHAR *from)
  184. {
  185. #if !defined(_UNICODE) && !defined(UNICODE)
  186. return strcpy(to, from);
  187. #else
  188. int count = wcslen(from);
  189. if (count != 0)
  190. if (WideCharToMultiByte(CP_ACP, 0, from, count, to, count, NULL, NULL) == 0)
  191. return NULL;
  192. return to;
  193. #endif
  194. }
  195. /*
  196. returns length of TCHAR string
  197. */
  198. size_t StrTLen(const TCHAR *str)
  199. {
  200. #if !defined(_UNICODE) && !defined(UNICODE)
  201. return strlen(str);
  202. #else
  203. return wcslen(str);
  204. #endif
  205. }
  206. /********************************************************************/
  207. typedef struct PaWinMmeStream PaWinMmeStream; /* forward declaration */
  208. /* prototypes for functions declared in this file */
  209. #ifdef __cplusplus
  210. extern "C"
  211. {
  212. #endif /* __cplusplus */
  213. PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
  214. #ifdef __cplusplus
  215. }
  216. #endif /* __cplusplus */
  217. static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
  218. static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
  219. PaStream** stream,
  220. const PaStreamParameters *inputParameters,
  221. const PaStreamParameters *outputParameters,
  222. double sampleRate,
  223. unsigned long framesPerBuffer,
  224. PaStreamFlags streamFlags,
  225. PaStreamCallback *streamCallback,
  226. void *userData );
  227. static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
  228. const PaStreamParameters *inputParameters,
  229. const PaStreamParameters *outputParameters,
  230. double sampleRate );
  231. static PaError CloseStream( PaStream* stream );
  232. static PaError StartStream( PaStream *stream );
  233. static PaError StopStream( PaStream *stream );
  234. static PaError AbortStream( PaStream *stream );
  235. static PaError IsStreamStopped( PaStream *s );
  236. static PaError IsStreamActive( PaStream *stream );
  237. static PaTime GetStreamTime( PaStream *stream );
  238. static double GetStreamCpuLoad( PaStream* stream );
  239. static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
  240. static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );
  241. static signed long GetStreamReadAvailable( PaStream* stream );
  242. static signed long GetStreamWriteAvailable( PaStream* stream );
  243. /* macros for setting last host error information */
  244. #ifdef UNICODE
  245. #define PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ) \
  246. { \
  247. wchar_t mmeErrorTextWide[ MAXERRORLENGTH ]; \
  248. char mmeErrorText[ MAXERRORLENGTH ]; \
  249. waveInGetErrorText( mmresult, mmeErrorTextWide, MAXERRORLENGTH ); \
  250. WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,\
  251. mmeErrorTextWide, -1, mmeErrorText, MAXERRORLENGTH, NULL, NULL ); \
  252. PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText ); \
  253. }
  254. #define PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ) \
  255. { \
  256. wchar_t mmeErrorTextWide[ MAXERRORLENGTH ]; \
  257. char mmeErrorText[ MAXERRORLENGTH ]; \
  258. waveOutGetErrorText( mmresult, mmeErrorTextWide, MAXERRORLENGTH ); \
  259. WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,\
  260. mmeErrorTextWide, -1, mmeErrorText, MAXERRORLENGTH, NULL, NULL ); \
  261. PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText ); \
  262. }
  263. #else /* !UNICODE */
  264. #define PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ) \
  265. { \
  266. char mmeErrorText[ MAXERRORLENGTH ]; \
  267. waveInGetErrorText( mmresult, mmeErrorText, MAXERRORLENGTH ); \
  268. PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText ); \
  269. }
  270. #define PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ) \
  271. { \
  272. char mmeErrorText[ MAXERRORLENGTH ]; \
  273. waveOutGetErrorText( mmresult, mmeErrorText, MAXERRORLENGTH ); \
  274. PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText ); \
  275. }
  276. #endif /* UNICODE */
  277. static void PaMme_SetLastSystemError( DWORD errorCode )
  278. {
  279. char *lpMsgBuf;
  280. FormatMessage(
  281. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  282. NULL,
  283. errorCode,
  284. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  285. (LPTSTR) &lpMsgBuf,
  286. 0,
  287. NULL
  288. );
  289. PaUtil_SetLastHostErrorInfo( paMME, errorCode, lpMsgBuf );
  290. LocalFree( lpMsgBuf );
  291. }
  292. #define PA_MME_SET_LAST_SYSTEM_ERROR( errorCode ) \
  293. PaMme_SetLastSystemError( errorCode )
  294. /* PaError returning wrappers for some commonly used win32 functions
  295. note that we allow passing a null ptr to have no effect.
  296. */
  297. static PaError CreateEventWithPaError( HANDLE *handle,
  298. LPSECURITY_ATTRIBUTES lpEventAttributes,
  299. BOOL bManualReset,
  300. BOOL bInitialState,
  301. LPCTSTR lpName )
  302. {
  303. PaError result = paNoError;
  304. *handle = NULL;
  305. *handle = CreateEvent( lpEventAttributes, bManualReset, bInitialState, lpName );
  306. if( *handle == NULL )
  307. {
  308. result = paUnanticipatedHostError;
  309. PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
  310. }
  311. return result;
  312. }
  313. static PaError ResetEventWithPaError( HANDLE handle )
  314. {
  315. PaError result = paNoError;
  316. if( handle )
  317. {
  318. if( ResetEvent( handle ) == 0 )
  319. {
  320. result = paUnanticipatedHostError;
  321. PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
  322. }
  323. }
  324. return result;
  325. }
  326. static PaError CloseHandleWithPaError( HANDLE handle )
  327. {
  328. PaError result = paNoError;
  329. if( handle )
  330. {
  331. if( CloseHandle( handle ) == 0 )
  332. {
  333. result = paUnanticipatedHostError;
  334. PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
  335. }
  336. }
  337. return result;
  338. }
  339. /* PaWinMmeHostApiRepresentation - host api datastructure specific to this implementation */
  340. typedef struct
  341. {
  342. PaUtilHostApiRepresentation inheritedHostApiRep;
  343. PaUtilStreamInterface callbackStreamInterface;
  344. PaUtilStreamInterface blockingStreamInterface;
  345. PaUtilAllocationGroup *allocations;
  346. int inputDeviceCount, outputDeviceCount;
  347. /** winMmeDeviceIds is an array of WinMme device ids.
  348. fields in the range [0, inputDeviceCount) are input device ids,
  349. and [inputDeviceCount, inputDeviceCount + outputDeviceCount) are output
  350. device ids.
  351. */
  352. UINT *winMmeDeviceIds;
  353. }
  354. PaWinMmeHostApiRepresentation;
  355. typedef struct
  356. {
  357. PaDeviceInfo inheritedDeviceInfo;
  358. DWORD dwFormats; /**<< standard formats bitmask from the WAVEINCAPS and WAVEOUTCAPS structures */
  359. char deviceInputChannelCountIsKnown; /**<< if the system returns 0xFFFF then we don't really know the number of supported channels (1=>known, 0=>unknown)*/
  360. char deviceOutputChannelCountIsKnown; /**<< if the system returns 0xFFFF then we don't really know the number of supported channels (1=>known, 0=>unknown)*/
  361. }
  362. PaWinMmeDeviceInfo;
  363. /*************************************************************************
  364. * Returns recommended device ID.
  365. * On the PC, the recommended device can be specified by the user by
  366. * setting an environment variable. For example, to use device #1.
  367. *
  368. * set PA_RECOMMENDED_OUTPUT_DEVICE=1
  369. *
  370. * The user should first determine the available device ID by using
  371. * the supplied application "pa_devs".
  372. */
  373. #define PA_ENV_BUF_SIZE_ (32)
  374. #define PA_REC_IN_DEV_ENV_NAME_ ("PA_RECOMMENDED_INPUT_DEVICE")
  375. #define PA_REC_OUT_DEV_ENV_NAME_ ("PA_RECOMMENDED_OUTPUT_DEVICE")
  376. static PaDeviceIndex GetEnvDefaultDeviceID( char *envName )
  377. {
  378. PaDeviceIndex recommendedIndex = paNoDevice;
  379. DWORD hresult;
  380. char envbuf[PA_ENV_BUF_SIZE_];
  381. #ifndef WIN32_PLATFORM_PSPC /* no GetEnvironmentVariable on PocketPC */
  382. /* Let user determine default device by setting environment variable. */
  383. hresult = GetEnvironmentVariableA( envName, envbuf, PA_ENV_BUF_SIZE_ );
  384. if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE_) )
  385. {
  386. recommendedIndex = atoi( envbuf );
  387. }
  388. #endif
  389. return recommendedIndex;
  390. }
  391. static void InitializeDefaultDeviceIdsFromEnv( PaWinMmeHostApiRepresentation *hostApi )
  392. {
  393. PaDeviceIndex device;
  394. /* input */
  395. device = GetEnvDefaultDeviceID( PA_REC_IN_DEV_ENV_NAME_ );
  396. if( device != paNoDevice &&
  397. ( device >= 0 && device < hostApi->inheritedHostApiRep.info.deviceCount ) &&
  398. hostApi->inheritedHostApiRep.deviceInfos[ device ]->maxInputChannels > 0 )
  399. {
  400. hostApi->inheritedHostApiRep.info.defaultInputDevice = device;
  401. }
  402. /* output */
  403. device = GetEnvDefaultDeviceID( PA_REC_OUT_DEV_ENV_NAME_ );
  404. if( device != paNoDevice &&
  405. ( device >= 0 && device < hostApi->inheritedHostApiRep.info.deviceCount ) &&
  406. hostApi->inheritedHostApiRep.deviceInfos[ device ]->maxOutputChannels > 0 )
  407. {
  408. hostApi->inheritedHostApiRep.info.defaultOutputDevice = device;
  409. }
  410. }
  411. /** Convert external PA ID to a windows multimedia device ID
  412. */
  413. static UINT LocalDeviceIndexToWinMmeDeviceId( PaWinMmeHostApiRepresentation *hostApi, PaDeviceIndex device )
  414. {
  415. assert( device >= 0 && device < hostApi->inputDeviceCount + hostApi->outputDeviceCount );
  416. return hostApi->winMmeDeviceIds[ device ];
  417. }
  418. static int SampleFormatAndWinWmmeSpecificFlagsToLinearWaveFormatTag( PaSampleFormat sampleFormat, unsigned long winMmeSpecificFlags )
  419. {
  420. int waveFormatTag = 0;
  421. if( winMmeSpecificFlags & paWinMmeWaveFormatDolbyAc3Spdif )
  422. waveFormatTag = PAWIN_WAVE_FORMAT_DOLBY_AC3_SPDIF;
  423. else if( winMmeSpecificFlags & paWinMmeWaveFormatWmaSpdif )
  424. waveFormatTag = PAWIN_WAVE_FORMAT_WMA_SPDIF;
  425. else
  426. waveFormatTag = PaWin_SampleFormatToLinearWaveFormatTag( sampleFormat );
  427. return waveFormatTag;
  428. }
  429. static PaError QueryInputWaveFormatEx( int deviceId, WAVEFORMATEX *waveFormatEx )
  430. {
  431. MMRESULT mmresult;
  432. switch( mmresult = waveInOpen( NULL, deviceId, waveFormatEx, 0, 0, WAVE_FORMAT_QUERY ) )
  433. {
  434. case MMSYSERR_NOERROR:
  435. return paNoError;
  436. case MMSYSERR_ALLOCATED: /* Specified resource is already allocated. */
  437. return paDeviceUnavailable;
  438. case MMSYSERR_NODRIVER: /* No device driver is present. */
  439. return paDeviceUnavailable;
  440. case MMSYSERR_NOMEM: /* Unable to allocate or lock memory. */
  441. return paInsufficientMemory;
  442. case WAVERR_BADFORMAT: /* Attempted to open with an unsupported waveform-audio format. */
  443. return paSampleFormatNotSupported;
  444. case MMSYSERR_BADDEVICEID: /* Specified device identifier is out of range. */
  445. /* falls through */
  446. default:
  447. PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
  448. return paUnanticipatedHostError;
  449. }
  450. }
  451. static PaError QueryOutputWaveFormatEx( int deviceId, WAVEFORMATEX *waveFormatEx )
  452. {
  453. MMRESULT mmresult;
  454. switch( mmresult = waveOutOpen( NULL, deviceId, waveFormatEx, 0, 0, WAVE_FORMAT_QUERY ) )
  455. {
  456. case MMSYSERR_NOERROR:
  457. return paNoError;
  458. case MMSYSERR_ALLOCATED: /* Specified resource is already allocated. */
  459. return paDeviceUnavailable;
  460. case MMSYSERR_NODRIVER: /* No device driver is present. */
  461. return paDeviceUnavailable;
  462. case MMSYSERR_NOMEM: /* Unable to allocate or lock memory. */
  463. return paInsufficientMemory;
  464. case WAVERR_BADFORMAT: /* Attempted to open with an unsupported waveform-audio format. */
  465. return paSampleFormatNotSupported;
  466. case MMSYSERR_BADDEVICEID: /* Specified device identifier is out of range. */
  467. /* falls through */
  468. default:
  469. PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
  470. return paUnanticipatedHostError;
  471. }
  472. }
  473. static PaError QueryFormatSupported( PaDeviceInfo *deviceInfo,
  474. PaError (*waveFormatExQueryFunction)(int, WAVEFORMATEX*),
  475. int winMmeDeviceId, int channels, double sampleRate, unsigned long winMmeSpecificFlags )
  476. {
  477. PaWinMmeDeviceInfo *winMmeDeviceInfo = (PaWinMmeDeviceInfo*)deviceInfo;
  478. PaWinWaveFormat waveFormat;
  479. PaSampleFormat sampleFormat;
  480. int waveFormatTag;
  481. /* @todo at the moment we only query with 16 bit sample format and directout speaker config*/
  482. sampleFormat = paInt16;
  483. waveFormatTag = SampleFormatAndWinWmmeSpecificFlagsToLinearWaveFormatTag( sampleFormat, winMmeSpecificFlags );
  484. if( waveFormatTag == PaWin_SampleFormatToLinearWaveFormatTag( paInt16 ) ){
  485. /* attempt bypass querying the device for linear formats */
  486. if( sampleRate == 11025.0
  487. && ( (channels == 1 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_1M16))
  488. || (channels == 2 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_1S16)) ) ){
  489. return paNoError;
  490. }
  491. if( sampleRate == 22050.0
  492. && ( (channels == 1 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_2M16))
  493. || (channels == 2 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_2S16)) ) ){
  494. return paNoError;
  495. }
  496. if( sampleRate == 44100.0
  497. && ( (channels == 1 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_4M16))
  498. || (channels == 2 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_4S16)) ) ){
  499. return paNoError;
  500. }
  501. }
  502. /* first, attempt to query the device using WAVEFORMATEXTENSIBLE,
  503. if this fails we fall back to WAVEFORMATEX */
  504. PaWin_InitializeWaveFormatExtensible( &waveFormat, channels, sampleFormat, waveFormatTag,
  505. sampleRate, PAWIN_SPEAKER_DIRECTOUT );
  506. if( waveFormatExQueryFunction( winMmeDeviceId, (WAVEFORMATEX*)&waveFormat ) == paNoError )
  507. return paNoError;
  508. PaWin_InitializeWaveFormatEx( &waveFormat, channels, sampleFormat, waveFormatTag, sampleRate );
  509. return waveFormatExQueryFunction( winMmeDeviceId, (WAVEFORMATEX*)&waveFormat );
  510. }
  511. #define PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_ (13) /* must match array length below */
  512. static double defaultSampleRateSearchOrder_[] =
  513. { 44100.0, 48000.0, 32000.0, 24000.0, 22050.0, 88200.0, 96000.0, 192000.0,
  514. 16000.0, 12000.0, 11025.0, 9600.0, 8000.0 };
  515. static void DetectDefaultSampleRate( PaWinMmeDeviceInfo *winMmeDeviceInfo, int winMmeDeviceId,
  516. PaError (*waveFormatExQueryFunction)(int, WAVEFORMATEX*), int maxChannels )
  517. {
  518. PaDeviceInfo *deviceInfo = &winMmeDeviceInfo->inheritedDeviceInfo;
  519. int i;
  520. deviceInfo->defaultSampleRate = 0.;
  521. for( i=0; i < PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_; ++i )
  522. {
  523. double sampleRate = defaultSampleRateSearchOrder_[ i ];
  524. PaError paerror = QueryFormatSupported( deviceInfo, waveFormatExQueryFunction, winMmeDeviceId, maxChannels, sampleRate, 0 );
  525. if( paerror == paNoError )
  526. {
  527. deviceInfo->defaultSampleRate = sampleRate;
  528. break;
  529. }
  530. }
  531. }
  532. #ifdef PAWIN_USE_WDMKS_DEVICE_INFO
  533. static int QueryWaveInKSFilterMaxChannels( int waveInDeviceId, int *maxChannels )
  534. {
  535. void *devicePath;
  536. DWORD devicePathSize;
  537. int result = 0;
  538. if( waveInMessage((HWAVEIN)waveInDeviceId, DRV_QUERYDEVICEINTERFACESIZE,
  539. (DWORD_PTR)&devicePathSize, 0 ) != MMSYSERR_NOERROR )
  540. return 0;
  541. devicePath = PaUtil_AllocateMemory( devicePathSize );
  542. if( !devicePath )
  543. return 0;
  544. /* apparently DRV_QUERYDEVICEINTERFACE returns a unicode interface path, although this is undocumented */
  545. if( waveInMessage((HWAVEIN)waveInDeviceId, DRV_QUERYDEVICEINTERFACE,
  546. (DWORD_PTR)devicePath, devicePathSize ) == MMSYSERR_NOERROR )
  547. {
  548. int count = PaWin_WDMKS_QueryFilterMaximumChannelCount( devicePath, /* isInput= */ 1 );
  549. if( count > 0 )
  550. {
  551. *maxChannels = count;
  552. result = 1;
  553. }
  554. }
  555. PaUtil_FreeMemory( devicePath );
  556. return result;
  557. }
  558. #endif /* PAWIN_USE_WDMKS_DEVICE_INFO */
  559. static PaError InitializeInputDeviceInfo( PaWinMmeHostApiRepresentation *winMmeHostApi,
  560. PaWinMmeDeviceInfo *winMmeDeviceInfo, UINT winMmeInputDeviceId, int *success )
  561. {
  562. PaError result = paNoError;
  563. char *deviceName; /* non-const ptr */
  564. MMRESULT mmresult;
  565. WAVEINCAPS wic;
  566. PaDeviceInfo *deviceInfo = &winMmeDeviceInfo->inheritedDeviceInfo;
  567. *success = 0;
  568. mmresult = waveInGetDevCaps( winMmeInputDeviceId, &wic, sizeof( WAVEINCAPS ) );
  569. if( mmresult == MMSYSERR_NOMEM )
  570. {
  571. result = paInsufficientMemory;
  572. goto error;
  573. }
  574. else if( mmresult != MMSYSERR_NOERROR )
  575. {
  576. /* instead of returning paUnanticipatedHostError we return
  577. paNoError, but leave success set as 0. This allows
  578. Pa_Initialize to just ignore this device, without failing
  579. the entire initialisation process.
  580. */
  581. return paNoError;
  582. }
  583. if( winMmeInputDeviceId == WAVE_MAPPER )
  584. {
  585. /* Append I/O suffix to WAVE_MAPPER device. */
  586. deviceName = (char *)PaUtil_GroupAllocateMemory(
  587. winMmeHostApi->allocations,
  588. (long) (StrTLen( wic.szPname ) + 1 + sizeof(constInputMapperSuffix_)) );
  589. if( !deviceName )
  590. {
  591. result = paInsufficientMemory;
  592. goto error;
  593. }
  594. StrTCpyToC( deviceName, wic.szPname );
  595. strcat( deviceName, constInputMapperSuffix_ );
  596. }
  597. else
  598. {
  599. deviceName = (char*)PaUtil_GroupAllocateMemory(
  600. winMmeHostApi->allocations,
  601. (long) (StrTLen( wic.szPname ) + 1) );
  602. if( !deviceName )
  603. {
  604. result = paInsufficientMemory;
  605. goto error;
  606. }
  607. StrTCpyToC( deviceName, wic.szPname );
  608. }
  609. deviceInfo->name = deviceName;
  610. if( wic.wChannels == 0xFFFF || wic.wChannels < 1 || wic.wChannels > 255 ){
  611. /* For Windows versions using WDM (possibly Windows 98 ME and later)
  612. * the kernel mixer sits between the application and the driver. As a result,
  613. * wave*GetDevCaps often kernel mixer channel counts, which are unlimited.
  614. * When this happens we assume the device is stereo and set a flag
  615. * so that other channel counts can be tried with OpenStream -- i.e. when
  616. * device*ChannelCountIsKnown is false, OpenStream will try whatever
  617. * channel count you supply.
  618. * see also InitializeOutputDeviceInfo() below.
  619. */
  620. PA_DEBUG(("Pa_GetDeviceInfo: Num input channels reported as %d! Changed to 2.\n", wic.wChannels ));
  621. deviceInfo->maxInputChannels = 2;
  622. winMmeDeviceInfo->deviceInputChannelCountIsKnown = 0;
  623. }else{
  624. deviceInfo->maxInputChannels = wic.wChannels;
  625. winMmeDeviceInfo->deviceInputChannelCountIsKnown = 1;
  626. }
  627. #ifdef PAWIN_USE_WDMKS_DEVICE_INFO
  628. winMmeDeviceInfo->deviceInputChannelCountIsKnown =
  629. QueryWaveInKSFilterMaxChannels( winMmeInputDeviceId, &deviceInfo->maxInputChannels );
  630. #endif /* PAWIN_USE_WDMKS_DEVICE_INFO */
  631. winMmeDeviceInfo->dwFormats = wic.dwFormats;
  632. DetectDefaultSampleRate( winMmeDeviceInfo, winMmeInputDeviceId,
  633. QueryInputWaveFormatEx, deviceInfo->maxInputChannels );
  634. *success = 1;
  635. error:
  636. return result;
  637. }
  638. #ifdef PAWIN_USE_WDMKS_DEVICE_INFO
  639. static int QueryWaveOutKSFilterMaxChannels( int waveOutDeviceId, int *maxChannels )
  640. {
  641. void *devicePath;
  642. DWORD devicePathSize;
  643. int result = 0;
  644. if( waveOutMessage((HWAVEOUT)waveOutDeviceId, DRV_QUERYDEVICEINTERFACESIZE,
  645. (DWORD_PTR)&devicePathSize, 0 ) != MMSYSERR_NOERROR )
  646. return 0;
  647. devicePath = PaUtil_AllocateMemory( devicePathSize );
  648. if( !devicePath )
  649. return 0;
  650. /* apparently DRV_QUERYDEVICEINTERFACE returns a unicode interface path, although this is undocumented */
  651. if( waveOutMessage((HWAVEOUT)waveOutDeviceId, DRV_QUERYDEVICEINTERFACE,
  652. (DWORD_PTR)devicePath, devicePathSize ) == MMSYSERR_NOERROR )
  653. {
  654. int count = PaWin_WDMKS_QueryFilterMaximumChannelCount( devicePath, /* isInput= */ 0 );
  655. if( count > 0 )
  656. {
  657. *maxChannels = count;
  658. result = 1;
  659. }
  660. }
  661. PaUtil_FreeMemory( devicePath );
  662. return result;
  663. }
  664. #endif /* PAWIN_USE_WDMKS_DEVICE_INFO */
  665. static PaError InitializeOutputDeviceInfo( PaWinMmeHostApiRepresentation *winMmeHostApi,
  666. PaWinMmeDeviceInfo *winMmeDeviceInfo, UINT winMmeOutputDeviceId, int *success )
  667. {
  668. PaError result = paNoError;
  669. char *deviceName; /* non-const ptr */
  670. MMRESULT mmresult;
  671. WAVEOUTCAPS woc;
  672. PaDeviceInfo *deviceInfo = &winMmeDeviceInfo->inheritedDeviceInfo;
  673. #ifdef PAWIN_USE_WDMKS_DEVICE_INFO
  674. int wdmksDeviceOutputChannelCountIsKnown;
  675. #endif
  676. *success = 0;
  677. mmresult = waveOutGetDevCaps( winMmeOutputDeviceId, &woc, sizeof( WAVEOUTCAPS ) );
  678. if( mmresult == MMSYSERR_NOMEM )
  679. {
  680. result = paInsufficientMemory;
  681. goto error;
  682. }
  683. else if( mmresult != MMSYSERR_NOERROR )
  684. {
  685. /* instead of returning paUnanticipatedHostError we return
  686. paNoError, but leave success set as 0. This allows
  687. Pa_Initialize to just ignore this device, without failing
  688. the entire initialisation process.
  689. */
  690. return paNoError;
  691. }
  692. if( winMmeOutputDeviceId == WAVE_MAPPER )
  693. {
  694. /* Append I/O suffix to WAVE_MAPPER device. */
  695. deviceName = (char *)PaUtil_GroupAllocateMemory(
  696. winMmeHostApi->allocations,
  697. (long) (StrTLen( woc.szPname ) + 1 + sizeof(constOutputMapperSuffix_)) );
  698. if( !deviceName )
  699. {
  700. result = paInsufficientMemory;
  701. goto error;
  702. }
  703. StrTCpyToC( deviceName, woc.szPname );
  704. strcat( deviceName, constOutputMapperSuffix_ );
  705. }
  706. else
  707. {
  708. deviceName = (char*)PaUtil_GroupAllocateMemory(
  709. winMmeHostApi->allocations,
  710. (long) (StrTLen( woc.szPname ) + 1) );
  711. if( !deviceName )
  712. {
  713. result = paInsufficientMemory;
  714. goto error;
  715. }
  716. StrTCpyToC( deviceName, woc.szPname );
  717. }
  718. deviceInfo->name = deviceName;
  719. if( woc.wChannels == 0xFFFF || woc.wChannels < 1 || woc.wChannels > 255 ){
  720. /* For Windows versions using WDM (possibly Windows 98 ME and later)
  721. * the kernel mixer sits between the application and the driver. As a result,
  722. * wave*GetDevCaps often kernel mixer channel counts, which are unlimited.
  723. * When this happens we assume the device is stereo and set a flag
  724. * so that other channel counts can be tried with OpenStream -- i.e. when
  725. * device*ChannelCountIsKnown is false, OpenStream will try whatever
  726. * channel count you supply.
  727. * see also InitializeInputDeviceInfo() above.
  728. */
  729. PA_DEBUG(("Pa_GetDeviceInfo: Num output channels reported as %d! Changed to 2.\n", woc.wChannels ));
  730. deviceInfo->maxOutputChannels = 2;
  731. winMmeDeviceInfo->deviceOutputChannelCountIsKnown = 0;
  732. }else{
  733. deviceInfo->maxOutputChannels = woc.wChannels;
  734. winMmeDeviceInfo->deviceOutputChannelCountIsKnown = 1;
  735. }
  736. #ifdef PAWIN_USE_WDMKS_DEVICE_INFO
  737. wdmksDeviceOutputChannelCountIsKnown = QueryWaveOutKSFilterMaxChannels(
  738. winMmeOutputDeviceId, &deviceInfo->maxOutputChannels );
  739. if( wdmksDeviceOutputChannelCountIsKnown && !winMmeDeviceInfo->deviceOutputChannelCountIsKnown )
  740. winMmeDeviceInfo->deviceOutputChannelCountIsKnown = 1;
  741. #endif /* PAWIN_USE_WDMKS_DEVICE_INFO */
  742. winMmeDeviceInfo->dwFormats = woc.dwFormats;
  743. DetectDefaultSampleRate( winMmeDeviceInfo, winMmeOutputDeviceId,
  744. QueryOutputWaveFormatEx, deviceInfo->maxOutputChannels );
  745. *success = 1;
  746. error:
  747. return result;
  748. }
  749. static void GetDefaultLatencies( PaTime *defaultLowLatency, PaTime *defaultHighLatency )
  750. {
  751. OSVERSIONINFO osvi;
  752. osvi.dwOSVersionInfoSize = sizeof( osvi );
  753. GetVersionEx( &osvi );
  754. /* Check for NT */
  755. if( (osvi.dwMajorVersion == 4) && (osvi.dwPlatformId == 2) )
  756. {
  757. *defaultLowLatency = PA_MME_WIN_NT_DEFAULT_LATENCY_;
  758. }
  759. else if(osvi.dwMajorVersion >= 5)
  760. {
  761. *defaultLowLatency = PA_MME_WIN_WDM_DEFAULT_LATENCY_;
  762. }
  763. else
  764. {
  765. *defaultLowLatency = PA_MME_WIN_9X_DEFAULT_LATENCY_;
  766. }
  767. *defaultHighLatency = *defaultLowLatency * 2;
  768. }
  769. PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
  770. {
  771. PaError result = paNoError;
  772. int i;
  773. PaWinMmeHostApiRepresentation *winMmeHostApi;
  774. int inputDeviceCount, outputDeviceCount, maximumPossibleDeviceCount;
  775. PaWinMmeDeviceInfo *deviceInfoArray;
  776. int deviceInfoInitializationSucceeded;
  777. PaTime defaultLowLatency, defaultHighLatency;
  778. DWORD waveInPreferredDevice, waveOutPreferredDevice;
  779. DWORD preferredDeviceStatusFlags;
  780. winMmeHostApi = (PaWinMmeHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinMmeHostApiRepresentation) );
  781. if( !winMmeHostApi )
  782. {
  783. result = paInsufficientMemory;
  784. goto error;
  785. }
  786. winMmeHostApi->allocations = PaUtil_CreateAllocationGroup();
  787. if( !winMmeHostApi->allocations )
  788. {
  789. result = paInsufficientMemory;
  790. goto error;
  791. }
  792. *hostApi = &winMmeHostApi->inheritedHostApiRep;
  793. (*hostApi)->info.structVersion = 1;
  794. (*hostApi)->info.type = paMME;
  795. (*hostApi)->info.name = "MME";
  796. /* initialise device counts and default devices under the assumption that
  797. there are no devices. These values are incremented below if and when
  798. devices are successfully initialized.
  799. */
  800. (*hostApi)->info.deviceCount = 0;
  801. (*hostApi)->info.defaultInputDevice = paNoDevice;
  802. (*hostApi)->info.defaultOutputDevice = paNoDevice;
  803. winMmeHostApi->inputDeviceCount = 0;
  804. winMmeHostApi->outputDeviceCount = 0;
  805. #if !defined(DRVM_MAPPER_PREFERRED_GET)
  806. /* DRVM_MAPPER_PREFERRED_GET is defined in mmddk.h but we avoid a dependency on the DDK by defining it here */
  807. #define DRVM_MAPPER_PREFERRED_GET (0x2000+21)
  808. #endif
  809. /* the following calls assume that if wave*Message fails the preferred device parameter won't be modified */
  810. preferredDeviceStatusFlags = 0;
  811. waveInPreferredDevice = -1;
  812. waveInMessage( (HWAVEIN)WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET, (DWORD_PTR)&waveInPreferredDevice, (DWORD_PTR)&preferredDeviceStatusFlags );
  813. preferredDeviceStatusFlags = 0;
  814. waveOutPreferredDevice = -1;
  815. waveOutMessage( (HWAVEOUT)WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET, (DWORD_PTR)&waveOutPreferredDevice, (DWORD_PTR)&preferredDeviceStatusFlags );
  816. maximumPossibleDeviceCount = 0;
  817. inputDeviceCount = waveInGetNumDevs();
  818. if( inputDeviceCount > 0 )
  819. maximumPossibleDeviceCount += inputDeviceCount + 1; /* assume there is a WAVE_MAPPER */
  820. outputDeviceCount = waveOutGetNumDevs();
  821. if( outputDeviceCount > 0 )
  822. maximumPossibleDeviceCount += outputDeviceCount + 1; /* assume there is a WAVE_MAPPER */
  823. if( maximumPossibleDeviceCount > 0 ){
  824. (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
  825. winMmeHostApi->allocations, sizeof(PaDeviceInfo*) * maximumPossibleDeviceCount );
  826. if( !(*hostApi)->deviceInfos )
  827. {
  828. result = paInsufficientMemory;
  829. goto error;
  830. }
  831. /* allocate all device info structs in a contiguous block */
  832. deviceInfoArray = (PaWinMmeDeviceInfo*)PaUtil_GroupAllocateMemory(
  833. winMmeHostApi->allocations, sizeof(PaWinMmeDeviceInfo) * maximumPossibleDeviceCount );
  834. if( !deviceInfoArray )
  835. {
  836. result = paInsufficientMemory;
  837. goto error;
  838. }
  839. winMmeHostApi->winMmeDeviceIds = (UINT*)PaUtil_GroupAllocateMemory(
  840. winMmeHostApi->allocations, sizeof(int) * maximumPossibleDeviceCount );
  841. if( !winMmeHostApi->winMmeDeviceIds )
  842. {
  843. result = paInsufficientMemory;
  844. goto error;
  845. }
  846. GetDefaultLatencies( &defaultLowLatency, &defaultHighLatency );
  847. if( inputDeviceCount > 0 ){
  848. /* -1 is the WAVE_MAPPER */
  849. for( i = -1; i < inputDeviceCount; ++i ){
  850. UINT winMmeDeviceId = (UINT)((i==-1) ? WAVE_MAPPER : i);
  851. PaWinMmeDeviceInfo *wmmeDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ];
  852. PaDeviceInfo *deviceInfo = &wmmeDeviceInfo->inheritedDeviceInfo;
  853. deviceInfo->structVersion = 2;
  854. deviceInfo->hostApi = hostApiIndex;
  855. deviceInfo->maxInputChannels = 0;
  856. wmmeDeviceInfo->deviceInputChannelCountIsKnown = 1;
  857. deviceInfo->maxOutputChannels = 0;
  858. wmmeDeviceInfo->deviceOutputChannelCountIsKnown = 1;
  859. deviceInfo->defaultLowInputLatency = defaultLowLatency;
  860. deviceInfo->defaultLowOutputLatency = defaultLowLatency;
  861. deviceInfo->defaultHighInputLatency = defaultHighLatency;
  862. deviceInfo->defaultHighOutputLatency = defaultHighLatency;
  863. result = InitializeInputDeviceInfo( winMmeHostApi, wmmeDeviceInfo,
  864. winMmeDeviceId, &deviceInfoInitializationSucceeded );
  865. if( result != paNoError )
  866. goto error;
  867. if( deviceInfoInitializationSucceeded ){
  868. if( (*hostApi)->info.defaultInputDevice == paNoDevice ){
  869. /* if there is currently no default device, use the first one available */
  870. (*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount;
  871. }else if( winMmeDeviceId == waveInPreferredDevice ){
  872. /* set the default device to the system preferred device */
  873. (*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount;
  874. }
  875. winMmeHostApi->winMmeDeviceIds[ (*hostApi)->info.deviceCount ] = winMmeDeviceId;
  876. (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo;
  877. winMmeHostApi->inputDeviceCount++;
  878. (*hostApi)->info.deviceCount++;
  879. }
  880. }
  881. }
  882. if( outputDeviceCount > 0 ){
  883. /* -1 is the WAVE_MAPPER */
  884. for( i = -1; i < outputDeviceCount; ++i ){
  885. UINT winMmeDeviceId = (UINT)((i==-1) ? WAVE_MAPPER : i);
  886. PaWinMmeDeviceInfo *wmmeDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ];
  887. PaDeviceInfo *deviceInfo = &wmmeDeviceInfo->inheritedDeviceInfo;
  888. deviceInfo->structVersion = 2;
  889. deviceInfo->hostApi = hostApiIndex;
  890. deviceInfo->maxInputChannels = 0;
  891. wmmeDeviceInfo->deviceInputChannelCountIsKnown = 1;
  892. deviceInfo->maxOutputChannels = 0;
  893. wmmeDeviceInfo->deviceOutputChannelCountIsKnown = 1;
  894. deviceInfo->defaultLowInputLatency = defaultLowLatency;
  895. deviceInfo->defaultLowOutputLatency = defaultLowLatency;
  896. deviceInfo->defaultHighInputLatency = defaultHighLatency;
  897. deviceInfo->defaultHighOutputLatency = defaultHighLatency;
  898. result = InitializeOutputDeviceInfo( winMmeHostApi, wmmeDeviceInfo,
  899. winMmeDeviceId, &deviceInfoInitializationSucceeded );
  900. if( result != paNoError )
  901. goto error;
  902. if( deviceInfoInitializationSucceeded ){
  903. if( (*hostApi)->info.defaultOutputDevice == paNoDevice ){
  904. /* if there is currently no default device, use the first one available */
  905. (*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount;
  906. }else if( winMmeDeviceId == waveOutPreferredDevice ){
  907. /* set the default device to the system preferred device */
  908. (*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount;
  909. }
  910. winMmeHostApi->winMmeDeviceIds[ (*hostApi)->info.deviceCount ] = winMmeDeviceId;
  911. (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo;
  912. winMmeHostApi->outputDeviceCount++;
  913. (*hostApi)->info.deviceCount++;
  914. }
  915. }
  916. }
  917. }
  918. InitializeDefaultDeviceIdsFromEnv( winMmeHostApi );
  919. (*hostApi)->Terminate = Terminate;
  920. (*hostApi)->OpenStream = OpenStream;
  921. (*hostApi)->IsFormatSupported = IsFormatSupported;
  922. PaUtil_InitializeStreamInterface( &winMmeHostApi->callbackStreamInterface, CloseStream, StartStream,
  923. StopStream, AbortStream, IsStreamStopped, IsStreamActive,
  924. GetStreamTime, GetStreamCpuLoad,
  925. PaUtil_DummyRead, PaUtil_DummyWrite,
  926. PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
  927. PaUtil_InitializeStreamInterface( &winMmeHostApi->blockingStreamInterface, CloseStream, StartStream,
  928. StopStream, AbortStream, IsStreamStopped, IsStreamActive,
  929. GetStreamTime, PaUtil_DummyGetCpuLoad,
  930. ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
  931. return result;
  932. error:
  933. if( winMmeHostApi )
  934. {
  935. if( winMmeHostApi->allocations )
  936. {
  937. PaUtil_FreeAllAllocations( winMmeHostApi->allocations );
  938. PaUtil_DestroyAllocationGroup( winMmeHostApi->allocations );
  939. }
  940. PaUtil_FreeMemory( winMmeHostApi );
  941. }
  942. return result;
  943. }
  944. static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
  945. {
  946. PaWinMmeHostApiRepresentation *winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi;
  947. if( winMmeHostApi->allocations )
  948. {
  949. PaUtil_FreeAllAllocations( winMmeHostApi->allocations );
  950. PaUtil_DestroyAllocationGroup( winMmeHostApi->allocations );
  951. }
  952. PaUtil_FreeMemory( winMmeHostApi );
  953. }
  954. static PaError IsInputChannelCountSupported( PaWinMmeDeviceInfo* deviceInfo, int channelCount )
  955. {
  956. PaError result = paNoError;
  957. if( channelCount > 0
  958. && deviceInfo->deviceInputChannelCountIsKnown
  959. && channelCount > deviceInfo->inheritedDeviceInfo.maxInputChannels ){
  960. result = paInvalidChannelCount;
  961. }
  962. return result;
  963. }
  964. static PaError IsOutputChannelCountSupported( PaWinMmeDeviceInfo* deviceInfo, int channelCount )
  965. {
  966. PaError result = paNoError;
  967. if( channelCount > 0
  968. && deviceInfo->deviceOutputChannelCountIsKnown
  969. && channelCount > deviceInfo->inheritedDeviceInfo.maxOutputChannels ){
  970. result = paInvalidChannelCount;
  971. }
  972. return result;
  973. }
  974. static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
  975. const PaStreamParameters *inputParameters,
  976. const PaStreamParameters *outputParameters,
  977. double sampleRate )
  978. {
  979. PaWinMmeHostApiRepresentation *winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi;
  980. PaDeviceInfo *inputDeviceInfo, *outputDeviceInfo;
  981. int inputChannelCount, outputChannelCount;
  982. int inputMultipleDeviceChannelCount, outputMultipleDeviceChannelCount;
  983. PaSampleFormat inputSampleFormat, outputSampleFormat;
  984. PaWinMmeStreamInfo *inputStreamInfo, *outputStreamInfo;
  985. UINT winMmeInputDeviceId, winMmeOutputDeviceId;
  986. unsigned int i;
  987. PaError paerror;
  988. /* The calls to QueryFormatSupported below are intended to detect invalid
  989. sample rates. If we assume that the channel count and format are OK,
  990. then the only thing that could fail is the sample rate. This isn't
  991. strictly true, but I can't think of a better way to test that the
  992. sample rate is valid.
  993. */
  994. if( inputParameters )
  995. {
  996. inputChannelCount = inputParameters->channelCount;
  997. inputSampleFormat = inputParameters->sampleFormat;
  998. inputStreamInfo = inputParameters->hostApiSpecificStreamInfo;
  999. /* all standard sample formats are supported by the buffer adapter,
  1000. this implementation doesn't support any custom sample formats */
  1001. if( inputSampleFormat & paCustomFormat )
  1002. return paSampleFormatNotSupported;
  1003. if( inputParameters->device == paUseHostApiSpecificDeviceSpecification
  1004. && inputStreamInfo && (inputStreamInfo->flags & paWinMmeUseMultipleDevices) )
  1005. {
  1006. inputMultipleDeviceChannelCount = 0;
  1007. for( i=0; i< inputStreamInfo->deviceCount; ++i )
  1008. {
  1009. inputMultipleDeviceChannelCount += inputStreamInfo->devices[i].channelCount;
  1010. inputDeviceInfo = hostApi->deviceInfos[ inputStreamInfo->devices[i].device ];
  1011. /* check that input device can support inputChannelCount */
  1012. if( inputStreamInfo->devices[i].channelCount < 1 )
  1013. return paInvalidChannelCount;
  1014. paerror = IsInputChannelCountSupported( (PaWinMmeDeviceInfo*)inputDeviceInfo,
  1015. inputStreamInfo->devices[i].channelCount );
  1016. if( paerror != paNoError )
  1017. return paerror;
  1018. /* test for valid sample rate, see comment above */
  1019. winMmeInputDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, inputStreamInfo->devices[i].device );
  1020. paerror = QueryFormatSupported( inputDeviceInfo, QueryInputWaveFormatEx,
  1021. winMmeInputDeviceId, inputStreamInfo->devices[i].channelCount, sampleRate,
  1022. ((inputStreamInfo) ? inputStreamInfo->flags : 0) );
  1023. if( paerror != paNoError )
  1024. return paInvalidSampleRate;
  1025. }
  1026. if( inputMultipleDeviceChannelCount != inputChannelCount )
  1027. return paIncompatibleHostApiSpecificStreamInfo;
  1028. }
  1029. else
  1030. {
  1031. if( inputStreamInfo && (inputStreamInfo->flags & paWinMmeUseMultipleDevices) )
  1032. return paIncompatibleHostApiSpecificStreamInfo; /* paUseHostApiSpecificDeviceSpecification was not supplied as the input device */
  1033. inputDeviceInfo = hostApi->deviceInfos[ inputParameters->device ];
  1034. /* check that input device can support inputChannelCount */
  1035. paerror = IsInputChannelCountSupported( (PaWinMmeDeviceInfo*)inputDeviceInfo, inputChannelCount );
  1036. if( paerror != paNoError )
  1037. return paerror;
  1038. /* test for valid sample rate, see comment above */
  1039. winMmeInputDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, inputParameters->device );
  1040. paerror = QueryFormatSupported( inputDeviceInfo, QueryInputWaveFormatEx,
  1041. winMmeInputDeviceId, inputChannelCount, sampleRate,
  1042. ((inputStreamInfo) ? inputStreamInfo->flags : 0) );
  1043. if( paerror != paNoError )
  1044. return paInvalidSampleRate;
  1045. }
  1046. }
  1047. if( outputParameters )
  1048. {
  1049. outputChannelCount = outputParameters->channelCount;
  1050. outputSampleFormat = outputParameters->sampleFormat;
  1051. outputStreamInfo = outputParameters->hostApiSpecificStreamInfo;
  1052. /* all standard sample formats are supported by the buffer adapter,
  1053. this implementation doesn't support any custom sample formats */
  1054. if( outputSampleFormat & paCustomFormat )
  1055. return paSampleFormatNotSupported;
  1056. if( outputParameters->device == paUseHostApiSpecificDeviceSpecification
  1057. && outputStreamInfo && (outputStreamInfo->flags & paWinMmeUseMultipleDevices) )
  1058. {
  1059. outputMultipleDeviceChannelCount = 0;
  1060. for( i=0; i< outputStreamInfo->deviceCount; ++i )
  1061. {
  1062. outputMultipleDeviceChannelCount += outputStreamInfo->devices[i].channelCount;
  1063. outputDeviceInfo = hostApi->deviceInfos[ outputStreamInfo->devices[i].device ];
  1064. /* check that output device can support outputChannelCount */
  1065. if( outputStreamInfo->devices[i].channelCount < 1 )
  1066. return paInvalidChannelCount;
  1067. paerror = IsOutputChannelCountSupported( (PaWinMmeDeviceInfo*)outputDeviceInfo,
  1068. outputStreamInfo->devices[i].channelCount );
  1069. if( paerror != paNoError )
  1070. return paerror;
  1071. /* test for valid sample rate, see comment above */
  1072. winMmeOutputDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, outputStreamInfo->devices[i].device );
  1073. paerror = QueryFormatSupported( outputDeviceInfo, QueryOutputWaveFormatEx,
  1074. winMmeOutputDeviceId, outputStreamInfo->devices[i].channelCount, sampleRate,
  1075. ((outputStreamInfo) ? outputStreamInfo->flags : 0) );
  1076. if( paerror != paNoError )
  1077. return paInvalidSampleRate;
  1078. }
  1079. if( outputMultipleDeviceChannelCount != outputChannelCount )
  1080. return paIncompatibleHostApiSpecificStreamInfo;
  1081. }
  1082. else
  1083. {
  1084. if( outputStreamInfo && (outputStreamInfo->flags & paWinMmeUseMultipleDevices) )
  1085. return paIncompatibleHostApiSpecificStreamInfo; /* paUseHostApiSpecificDeviceSpecification was not supplied as the output device */
  1086. outputDeviceInfo = hostApi->deviceInfos[ outputParameters->device ];
  1087. /* check that output device can support outputChannelCount */
  1088. paerror = IsOutputChannelCountSupported( (PaWinMmeDeviceInfo*)outputDeviceInfo, outputChannelCount );
  1089. if( paerror != paNoError )
  1090. return paerror;
  1091. /* test for valid sample rate, see comment above */
  1092. winMmeOutputDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, outputParameters->device );
  1093. paerror = QueryFormatSupported( outputDeviceInfo, QueryOutputWaveFormatEx,
  1094. winMmeOutputDeviceId, outputChannelCount, sampleRate,
  1095. ((outputStreamInfo) ? outputStreamInfo->flags : 0) );
  1096. if( paerror != paNoError )
  1097. return paInvalidSampleRate;
  1098. }
  1099. }
  1100. /*
  1101. - if a full duplex stream is requested, check that the combination
  1102. of input and output parameters is supported
  1103. - check that the device supports sampleRate
  1104. for mme all we can do is test that the input and output devices
  1105. support the requested sample rate and number of channels. we
  1106. cannot test for full duplex compatibility.
  1107. */
  1108. return paFormatIsSupported;
  1109. }
  1110. static unsigned long ComputeHostBufferCountForFixedBufferSizeFrames(
  1111. unsigned long suggestedLatencyFrames,
  1112. unsigned long hostBufferSizeFrames,
  1113. unsigned long minimumBufferCount )
  1114. {
  1115. /* Calculate the number of buffers of length hostFramesPerBuffer
  1116. that fit in suggestedLatencyFrames, rounding up to the next integer.
  1117. The value (hostBufferSizeFrames - 1) below is to ensure the buffer count is rounded up.
  1118. */
  1119. unsigned long resultBufferCount = ((suggestedLatencyFrames + (hostBufferSizeFrames - 1)) / hostBufferSizeFrames);
  1120. /* We always need one extra buffer for processing while the rest are queued/playing.
  1121. i.e. latency is framesPerBuffer * (bufferCount - 1)
  1122. */
  1123. resultBufferCount += 1;
  1124. if( resultBufferCount < minimumBufferCount ) /* clamp to minimum buffer count */
  1125. resultBufferCount = minimumBufferCount;
  1126. return resultBufferCount;
  1127. }
  1128. static unsigned long ComputeHostBufferSizeGivenHardUpperLimit(
  1129. unsigned long userFramesPerBuffer,
  1130. unsigned long absoluteMaximumBufferSizeFrames )
  1131. {
  1132. static unsigned long primes_[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23,
  1133. 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 0 }; /* zero terminated */
  1134. unsigned long result = userFramesPerBuffer;
  1135. int i;
  1136. assert( absoluteMaximumBufferSizeFrames > 67 ); /* assume maximum is large and we're only factoring by small primes */
  1137. /* search for the largest integer factor of userFramesPerBuffer less
  1138. than or equal to absoluteMaximumBufferSizeFrames */
  1139. /* repeatedly divide by smallest prime factors until a buffer size
  1140. smaller than absoluteMaximumBufferSizeFrames is found */
  1141. while( result > absoluteMaximumBufferSizeFrames ){
  1142. /* search for the smallest prime factor of result */
  1143. for( i=0; primes_[i] != 0; ++i )
  1144. {
  1145. unsigned long p = primes_[i];
  1146. unsigned long divided = result / p;
  1147. if( divided*p == result )
  1148. {
  1149. result = divided;
  1150. break; /* continue with outer while loop */
  1151. }
  1152. }
  1153. if( primes_[i] == 0 )
  1154. { /* loop failed to find a prime factor, return an approximate result */
  1155. unsigned long d = (userFramesPerBuffer + (absoluteMaximumBufferSizeFrames-1))
  1156. / absoluteMaximumBufferSizeFrames;
  1157. return userFramesPerBuffer / d;
  1158. }
  1159. }
  1160. return result;
  1161. }
  1162. static PaError SelectHostBufferSizeFramesAndHostBufferCount(
  1163. unsigned long suggestedLatencyFrames,
  1164. unsigned long userFramesPerBuffer,
  1165. unsigned long minimumBufferCount,
  1166. unsigned long preferredMaximumBufferSizeFrames, /* try not to exceed this. for example, don't exceed when coalescing buffers */
  1167. unsigned long absoluteMaximumBufferSizeFrames, /* never exceed this, a hard limit */
  1168. unsigned long *hostBufferSizeFrames,
  1169. unsigned long *hostBufferCount )
  1170. {
  1171. unsigned long effectiveUserFramesPerBuffer;
  1172. unsigned long numberOfUserBuffersPerHostBuffer;
  1173. if( userFramesPerBuffer == paFramesPerBufferUnspecified ){
  1174. effectiveUserFramesPerBuffer = PA_MME_HOST_BUFFER_GRANULARITY_FRAMES_WHEN_UNSPECIFIED_;
  1175. }else{
  1176. if( userFramesPerBuffer > absoluteMaximumBufferSizeFrames ){
  1177. /* user has requested a user buffer that's larger than absoluteMaximumBufferSizeFrames.
  1178. try to choose a buffer size that is equal or smaller than absoluteMaximumBufferSizeFrames
  1179. but is also an integer factor of userFramesPerBuffer, so as to distribute computation evenly.
  1180. the buffer processor will handle the block adaption between host and user buffer sizes.
  1181. see http://www.portaudio.com/trac/ticket/189 for discussion.
  1182. */
  1183. effectiveUserFramesPerBuffer = ComputeHostBufferSizeGivenHardUpperLimit( userFramesPerBuffer, absoluteMaximumBufferSizeFrames );
  1184. assert( effectiveUserFramesPerBuffer <= absoluteMaximumBufferSizeFrames );
  1185. /* try to ensure that duration of host buffering is at least as
  1186. large as duration of user buffer. */
  1187. if( suggestedLatencyFrames < userFramesPerBuffer )
  1188. suggestedLatencyFrames = userFramesPerBuffer;
  1189. }else{
  1190. effectiveUserFramesPerBuffer = userFramesPerBuffer;
  1191. }
  1192. }
  1193. /* compute a host buffer count based on suggestedLatencyFrames and our granularity */
  1194. *hostBufferSizeFrames = effectiveUserFramesPerBuffer;
  1195. *hostBufferCount = ComputeHostBufferCountForFixedBufferSizeFrames(
  1196. suggestedLatencyFrames, *hostBufferSizeFrames, minimumBufferCount );
  1197. if( *hostBufferSizeFrames >= userFramesPerBuffer )
  1198. {
  1199. /*
  1200. If there are too many host buffers we would like to coalesce
  1201. them by packing an integer number of user buffers into each host buffer.
  1202. We try to coalesce such that hostBufferCount will lie between
  1203. PA_MME_TARGET_HOST_BUFFER_COUNT_ and (PA_MME_TARGET_HOST_BUFFER_COUNT_*2)-1.
  1204. We limit coalescing to avoid exceeding either absoluteMaximumBufferSizeFrames and
  1205. preferredMaximumBufferSizeFrames.
  1206. First, compute a coalescing factor: the number of user buffers per host buffer.
  1207. The goal is to achieve PA_MME_TARGET_HOST_BUFFER_COUNT_ total buffer count.
  1208. Since our latency is computed based on (*hostBufferCount - 1) we compute a
  1209. coalescing factor based on (*hostBufferCount - 1) and (PA_MME_TARGET_HOST_BUFFER_COUNT_-1).
  1210. The + (PA_MME_TARGET_HOST_BUFFER_COUNT_-2) term below is intended to round up.
  1211. */
  1212. numberOfUserBuffersPerHostBuffer = ((*hostBufferCount - 1) + (PA_MME_TARGET_HOST_BUFFER_COUNT_-2)) / (PA_MME_TARGET_HOST_BUFFER_COUNT_ - 1);
  1213. if( numberOfUserBuffersPerHostBuffer > 1 )
  1214. {
  1215. unsigned long maxCoalescedBufferSizeFrames = (absoluteMaximumBufferSizeFrames < preferredMaximumBufferSizeFrames) /* minimum of our limits */
  1216. ? absoluteMaximumBufferSizeFrames
  1217. : preferredMaximumBufferSizeFrames;
  1218. unsigned long maxUserBuffersPerHostBuffer = maxCoalescedBufferSizeFrames / effectiveUserFramesPerBuffer; /* don't coalesce more than this */
  1219. if( numberOfUserBuffersPerHostBuffer > maxUserBuffersPerHostBuffer )
  1220. numberOfUserBuffersPerHostBuffer = maxUserBuffersPerHostBuffer;
  1221. *hostBufferSizeFrames = effectiveUserFramesPerBuffer * numberOfUserBuffersPerHostBuffer;
  1222. /* recompute hostBufferCount to approximate suggestedLatencyFrames now that hostBufferSizeFrames is larger */
  1223. *hostBufferCount = ComputeHostBufferCountForFixedBufferSizeFrames(
  1224. suggestedLatencyFrames, *hostBufferSizeFrames, minimumBufferCount );
  1225. }
  1226. }
  1227. return paNoError;
  1228. }
  1229. static PaError CalculateMaxHostSampleFrameSizeBytes(
  1230. int channelCount,
  1231. PaSampleFormat hostSampleFormat,
  1232. const PaWinMmeStreamInfo *streamInfo,
  1233. int *hostSampleFrameSizeBytes )
  1234. {
  1235. unsigned int i;
  1236. /* PA WMME streams may aggregate multiple WMME devices. When the stream addresses
  1237. more than one device in a single direction, maxDeviceChannelCount is the maximum
  1238. number of channels used by a single device.
  1239. */
  1240. int maxDeviceChannelCount = channelCount;
  1241. int hostSampleSizeBytes = Pa_GetSampleSize( hostSampleFormat );
  1242. if( hostSampleSizeBytes < 0 )
  1243. {
  1244. return hostSampleSizeBytes; /* the value of hostSampleSize here is an error code, not a sample size */
  1245. }
  1246. if( streamInfo && ( streamInfo->flags & paWinMmeUseMultipleDevices ) )
  1247. {
  1248. maxDeviceChannelCount = streamInfo->devices[0].channelCount;
  1249. for( i=1; i< streamInfo->deviceCount; ++i )
  1250. {
  1251. if( streamInfo->devices[i].channelCount > maxDeviceChannelCount )
  1252. maxDeviceChannelCount = streamInfo->devices[i].channelCount;
  1253. }
  1254. }
  1255. *hostSampleFrameSizeBytes = hostSampleSizeBytes * maxDeviceChannelCount;
  1256. return paNoError;
  1257. }
  1258. /* CalculateBufferSettings() fills the framesPerHostInputBuffer, hostInputBufferCount,
  1259. framesPerHostOutputBuffer and hostOutputBufferCount parameters based on the values
  1260. of the other parameters.
  1261. */
  1262. static PaError CalculateBufferSettings(
  1263. unsigned long *hostFramesPerInputBuffer, unsigned long *hostInputBufferCount,
  1264. unsigned long *hostFramesPerOutputBuffer, unsigned long *hostOutputBufferCount,
  1265. int inputChannelCount, PaSampleFormat hostInputSampleFormat,
  1266. PaTime suggestedInputLatency, const PaWinMmeStreamInfo *inputStreamInfo,
  1267. int outputChannelCount, PaSampleFormat hostOutputSampleFormat,
  1268. PaTime suggestedOutputLatency, const PaWinMmeStreamInfo *outputStreamInfo,
  1269. double sampleRate, unsigned long userFramesPerBuffer )
  1270. {
  1271. PaError result = paNoError;
  1272. if( inputChannelCount > 0 ) /* stream has input */
  1273. {
  1274. int hostInputFrameSizeBytes;
  1275. result = CalculateMaxHostSampleFrameSizeBytes(
  1276. inputChannelCount, hostInputSampleFormat, inputStreamInfo, &hostInputFrameSizeBytes );
  1277. if( result != paNoError )
  1278. goto error;
  1279. if( inputStreamInfo
  1280. && ( inputStreamInfo->flags & paWinMmeUseLowLevelLatencyParameters ) )
  1281. {
  1282. /* input - using low level latency parameters if provided */
  1283. if( inputStreamInfo->bufferCount <= 0
  1284. || inputStreamInfo->framesPerBuffer <= 0 )
  1285. {
  1286. result = paIncompatibleHostApiSpecificStreamInfo;
  1287. goto error;
  1288. }
  1289. *hostFramesPerInputBuffer = inputStreamInfo->framesPerBuffer;
  1290. *hostInputBufferCount = inputStreamInfo->bufferCount;
  1291. }
  1292. else
  1293. {
  1294. /* input - not using low level latency parameters, so compute
  1295. hostFramesPerInputBuffer and hostInputBufferCount
  1296. based on userFramesPerBuffer and suggestedInputLatency. */
  1297. unsigned long minimumBufferCount = (outputChannelCount > 0)
  1298. ? PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_
  1299. : PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_HALF_DUPLEX_;
  1300. result = SelectHostBufferSizeFramesAndHostBufferCount(
  1301. (unsigned long)(suggestedInputLatency * sampleRate), /* (truncate) */
  1302. userFramesPerBuffer,
  1303. minimumBufferCount,
  1304. (unsigned long)(PA_MME_MAX_HOST_BUFFER_SECS_ * sampleRate), /* in frames. preferred maximum */
  1305. (PA_MME_MAX_HOST_BUFFER_BYTES_ / hostInputFrameSizeBytes), /* in frames. a hard limit. note truncation due to
  1306. division is intentional here to limit max bytes */
  1307. hostFramesPerInputBuffer,
  1308. hostInputBufferCount );
  1309. if( result != paNoError )
  1310. goto error;
  1311. }
  1312. }
  1313. else
  1314. {
  1315. *hostFramesPerInputBuffer = 0;
  1316. *hostInputBufferCount = 0;
  1317. }
  1318. if( outputChannelCount > 0 ) /* stream has output */
  1319. {
  1320. if( outputStreamInfo
  1321. && ( outputStreamInfo->flags & paWinMmeUseLowLevelLatencyParameters ) )
  1322. {
  1323. /* output - using low level latency parameters */
  1324. if( outputStreamInfo->bufferCount <= 0
  1325. || outputStreamInfo->framesPerBuffer <= 0 )
  1326. {
  1327. result = paIncompatibleHostApiSpecificStreamInfo;
  1328. goto error;
  1329. }
  1330. *hostFramesPerOutputBuffer = outputStreamInfo->framesPerBuffer;
  1331. *hostOutputBufferCount = outputStreamInfo->bufferCount;
  1332. if( inputChannelCount > 0 ) /* full duplex */
  1333. {
  1334. /* harmonize hostFramesPerInputBuffer and hostFramesPerOutputBuffer */
  1335. if( *hostFramesPerInputBuffer != *hostFramesPerOutputBuffer )
  1336. {
  1337. if( inputStreamInfo
  1338. && ( inputStreamInfo->flags & paWinMmeUseLowLevelLatencyParameters ) )
  1339. {
  1340. /* a custom StreamInfo was used for specifying both input
  1341. and output buffer sizes. We require that the larger buffer size
  1342. must be a multiple of the smaller buffer size */
  1343. if( *hostFramesPerInputBuffer < *hostFramesPerOutputBuffer )
  1344. {
  1345. if( *hostFramesPerOutputBuffer % *hostFramesPerInputBuffer != 0 )
  1346. {
  1347. result = paIncompatibleHostApiSpecificStreamInfo;
  1348. goto error;
  1349. }
  1350. }
  1351. else
  1352. {
  1353. assert( *hostFramesPerInputBuffer > *hostFramesPerOutputBuffer );
  1354. if( *hostFramesPerInputBuffer % *hostFramesPerOutputBuffer != 0 )
  1355. {
  1356. result = paIncompatibleHostApiSpecificStreamInfo;
  1357. goto error;
  1358. }
  1359. }
  1360. }
  1361. else
  1362. {
  1363. /* a custom StreamInfo was not used for specifying the input buffer size,
  1364. so use the output buffer size, and approximately the suggested input latency. */
  1365. *hostFramesPerInputBuffer = *hostFramesPerOutputBuffer;
  1366. *hostInputBufferCount = ComputeHostBufferCountForFixedBufferSizeFrames(
  1367. (unsigned long)(suggestedInputLatency * sampleRate),
  1368. *hostFramesPerInputBuffer,
  1369. PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_ );
  1370. }
  1371. }
  1372. }
  1373. }
  1374. else
  1375. {
  1376. /* output - no low level latency parameters, so compute hostFramesPerOutputBuffer and hostOutputBufferCount
  1377. based on userFramesPerBuffer and suggestedOutputLatency. */
  1378. int hostOutputFrameSizeBytes;
  1379. result = CalculateMaxHostSampleFrameSizeBytes(
  1380. outputChannelCount, hostOutputSampleFormat, outputStreamInfo, &hostOutputFrameSizeBytes );
  1381. if( result != paNoError )
  1382. goto error;
  1383. /* compute the output buffer size and count */
  1384. result = SelectHostBufferSizeFramesAndHostBufferCount(
  1385. (unsigned long)(suggestedOutputLatency * sampleRate), /* (truncate) */
  1386. userFramesPerBuffer,
  1387. PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_,
  1388. (unsigned long)(PA_MME_MAX_HOST_BUFFER_SECS_ * sampleRate), /* in frames. preferred maximum */
  1389. (PA_MME_MAX_HOST_BUFFER_BYTES_ / hostOutputFrameSizeBytes), /* in frames. a hard limit. note truncation due to
  1390. division is intentional here to limit max bytes */
  1391. hostFramesPerOutputBuffer,
  1392. hostOutputBufferCount );
  1393. if( result != paNoError )
  1394. goto error;
  1395. if( inputChannelCount > 0 ) /* full duplex */
  1396. {
  1397. /* harmonize hostFramesPerInputBuffer and hostFramesPerOutputBuffer */
  1398. /* ensure that both input and output buffer sizes are the same.
  1399. if they don't match at this stage, choose the smallest one
  1400. and use that for input and output and recompute the corresponding
  1401. buffer count accordingly.
  1402. */
  1403. if( *hostFramesPerOutputBuffer != *hostFramesPerInputBuffer )
  1404. {
  1405. if( hostFramesPerInputBuffer < hostFramesPerOutputBuffer )
  1406. {
  1407. *hostFramesPerOutputBuffer = *hostFramesPerInputBuffer;
  1408. *hostOutputBufferCount = ComputeHostBufferCountForFixedBufferSizeFrames(
  1409. (unsigned long)(suggestedOutputLatency * sampleRate),
  1410. *hostOutputBufferCount,
  1411. PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_ );
  1412. }
  1413. else
  1414. {
  1415. *hostFramesPerInputBuffer = *hostFramesPerOutputBuffer;
  1416. *hostInputBufferCount = ComputeHostBufferCountForFixedBufferSizeFrames(
  1417. (unsigned long)(suggestedInputLatency * sampleRate),
  1418. *hostFramesPerInputBuffer,
  1419. PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_ );
  1420. }
  1421. }
  1422. }
  1423. }
  1424. }
  1425. else
  1426. {
  1427. *hostFramesPerOutputBuffer = 0;
  1428. *hostOutputBufferCount = 0;
  1429. }
  1430. error:
  1431. return result;
  1432. }
  1433. typedef struct
  1434. {
  1435. HANDLE bufferEvent;
  1436. void *waveHandles;
  1437. unsigned int deviceCount;
  1438. /* unsigned int channelCount; */
  1439. WAVEHDR **waveHeaders; /* waveHeaders[device][buffer] */
  1440. unsigned int bufferCount;
  1441. unsigned int currentBufferIndex;
  1442. unsigned int framesPerBuffer;
  1443. unsigned int framesUsedInCurrentBuffer;
  1444. }PaWinMmeSingleDirectionHandlesAndBuffers;
  1445. /* prototypes for functions operating on PaWinMmeSingleDirectionHandlesAndBuffers */
  1446. static void InitializeSingleDirectionHandlesAndBuffers( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers );
  1447. static PaError InitializeWaveHandles( PaWinMmeHostApiRepresentation *winMmeHostApi,
  1448. PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers,
  1449. unsigned long winMmeSpecificFlags,
  1450. unsigned long bytesPerHostSample,
  1451. double sampleRate, PaWinMmeDeviceAndChannelCount *devices,
  1452. unsigned int deviceCount, PaWinWaveFormatChannelMask channelMask, int isInput );
  1453. static PaError TerminateWaveHandles( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput, int currentlyProcessingAnError );
  1454. static PaError InitializeWaveHeaders( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers,
  1455. unsigned long hostBufferCount,
  1456. PaSampleFormat hostSampleFormat,
  1457. unsigned long framesPerHostBuffer,
  1458. PaWinMmeDeviceAndChannelCount *devices,
  1459. int isInput );
  1460. static void TerminateWaveHeaders( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput );
  1461. static void InitializeSingleDirectionHandlesAndBuffers( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers )
  1462. {
  1463. handlesAndBuffers->bufferEvent = 0;
  1464. handlesAndBuffers->waveHandles = 0;
  1465. handlesAndBuffers->deviceCount = 0;
  1466. handlesAndBuffers->waveHeaders = 0;
  1467. handlesAndBuffers->bufferCount = 0;
  1468. }
  1469. static PaError InitializeWaveHandles( PaWinMmeHostApiRepresentation *winMmeHostApi,
  1470. PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers,
  1471. unsigned long winMmeSpecificFlags,
  1472. unsigned long bytesPerHostSample,
  1473. double sampleRate, PaWinMmeDeviceAndChannelCount *devices,
  1474. unsigned int deviceCount, PaWinWaveFormatChannelMask channelMask, int isInput )
  1475. {
  1476. PaError result;
  1477. MMRESULT mmresult;
  1478. signed int i, j;
  1479. PaSampleFormat sampleFormat;
  1480. int waveFormatTag;
  1481. /* for error cleanup we expect that InitializeSingleDirectionHandlesAndBuffers()
  1482. has already been called to zero some fields */
  1483. result = CreateEventWithPaError( &handlesAndBuffers->bufferEvent, NULL, FALSE, FALSE, NULL );
  1484. if( result != paNoError ) goto error;
  1485. if( isInput )
  1486. handlesAndBuffers->waveHandles = (void*)PaUtil_AllocateMemory( sizeof(HWAVEIN) * deviceCount );
  1487. else
  1488. handlesAndBuffers->waveHandles = (void*)PaUtil_AllocateMemory( sizeof(HWAVEOUT) * deviceCount );
  1489. if( !handlesAndBuffers->waveHandles )
  1490. {
  1491. result = paInsufficientMemory;
  1492. goto error;
  1493. }
  1494. handlesAndBuffers->deviceCount = deviceCount;
  1495. for( i = 0; i < (signed int)deviceCount; ++i )
  1496. {
  1497. if( isInput )
  1498. ((HWAVEIN*)handlesAndBuffers->waveHandles)[i] = 0;
  1499. else
  1500. ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i] = 0;
  1501. }
  1502. /* @todo at the moment we only use 16 bit sample format */
  1503. sampleFormat = paInt16;
  1504. waveFormatTag = SampleFormatAndWinWmmeSpecificFlagsToLinearWaveFormatTag( sampleFormat, winMmeSpecificFlags );
  1505. for( i = 0; i < (signed int)deviceCount; ++i )
  1506. {
  1507. PaWinWaveFormat waveFormat;
  1508. UINT winMmeDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, devices[i].device );
  1509. /* @todo: consider providing a flag or #define to not try waveformat extensible
  1510. this could just initialize j to 1 the first time round. */
  1511. for( j = 0; j < 2; ++j )
  1512. {
  1513. switch(j){
  1514. case 0:
  1515. /* first, attempt to open the device using WAVEFORMATEXTENSIBLE,
  1516. if this fails we fall back to WAVEFORMATEX */
  1517. PaWin_InitializeWaveFormatExtensible( &waveFormat, devices[i].channelCount,
  1518. sampleFormat, waveFormatTag, sampleRate, channelMask );
  1519. break;
  1520. case 1:
  1521. /* retry with WAVEFORMATEX */
  1522. PaWin_InitializeWaveFormatEx( &waveFormat, devices[i].channelCount,
  1523. sampleFormat, waveFormatTag, sampleRate );
  1524. break;
  1525. }
  1526. /* REVIEW: consider not firing an event for input when a full duplex
  1527. stream is being used. this would probably depend on the
  1528. neverDropInput flag. */
  1529. if( isInput )
  1530. {
  1531. mmresult = waveInOpen( &((HWAVEIN*)handlesAndBuffers->waveHandles)[i], winMmeDeviceId,
  1532. (WAVEFORMATEX*)&waveFormat,
  1533. (DWORD_PTR)handlesAndBuffers->bufferEvent, (DWORD_PTR)0, CALLBACK_EVENT );
  1534. }
  1535. else
  1536. {
  1537. mmresult = waveOutOpen( &((HWAVEOUT*)handlesAndBuffers->waveHandles)[i], winMmeDeviceId,
  1538. (WAVEFORMATEX*)&waveFormat,
  1539. (DWORD_PTR)handlesAndBuffers->bufferEvent, (DWORD_PTR)0, CALLBACK_EVENT );
  1540. }
  1541. if( mmresult == MMSYSERR_NOERROR )
  1542. {
  1543. break; /* success */
  1544. }
  1545. else if( j == 0 )
  1546. {
  1547. continue; /* try again with WAVEFORMATEX */
  1548. }
  1549. else
  1550. {
  1551. switch( mmresult )
  1552. {
  1553. case MMSYSERR_ALLOCATED: /* Specified resource is already allocated. */
  1554. result = paDeviceUnavailable;
  1555. break;
  1556. case MMSYSERR_NODRIVER: /* No device driver is present. */
  1557. result = paDeviceUnavailable;
  1558. break;
  1559. case MMSYSERR_NOMEM: /* Unable to allocate or lock memory. */
  1560. result = paInsufficientMemory;
  1561. break;
  1562. case MMSYSERR_BADDEVICEID: /* Specified device identifier is out of range. */
  1563. /* falls through */
  1564. case WAVERR_BADFORMAT: /* Attempted to open with an unsupported waveform-audio format. */
  1565. /* This can also occur if we try to open the device with an unsupported
  1566. * number of channels. This is attempted when device*ChannelCountIsKnown is
  1567. * set to 0.
  1568. */
  1569. /* falls through */
  1570. default:
  1571. result = paUnanticipatedHostError;
  1572. if( isInput )
  1573. {
  1574. PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
  1575. }
  1576. else
  1577. {
  1578. PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
  1579. }
  1580. }
  1581. goto error;
  1582. }
  1583. }
  1584. }
  1585. return result;
  1586. error:
  1587. TerminateWaveHandles( handlesAndBuffers, isInput, 1 /* currentlyProcessingAnError */ );
  1588. return result;
  1589. }
  1590. static PaError TerminateWaveHandles( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput, int currentlyProcessingAnError )
  1591. {
  1592. PaError result = paNoError;
  1593. MMRESULT mmresult;
  1594. signed int i;
  1595. if( handlesAndBuffers->waveHandles )
  1596. {
  1597. for( i = handlesAndBuffers->deviceCount-1; i >= 0; --i )
  1598. {
  1599. if( isInput )
  1600. {
  1601. if( ((HWAVEIN*)handlesAndBuffers->waveHandles)[i] )
  1602. mmresult = waveInClose( ((HWAVEIN*)handlesAndBuffers->waveHandles)[i] );
  1603. else
  1604. mmresult = MMSYSERR_NOERROR;
  1605. }
  1606. else
  1607. {
  1608. if( ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i] )
  1609. mmresult = waveOutClose( ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i] );
  1610. else
  1611. mmresult = MMSYSERR_NOERROR;
  1612. }
  1613. if( mmresult != MMSYSERR_NOERROR &&
  1614. !currentlyProcessingAnError ) /* don't update the error state if we're already processing an error */
  1615. {
  1616. result = paUnanticipatedHostError;
  1617. if( isInput )
  1618. {
  1619. PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
  1620. }
  1621. else
  1622. {
  1623. PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
  1624. }
  1625. /* note that we don't break here, we try to continue closing devices */
  1626. }
  1627. }
  1628. PaUtil_FreeMemory( handlesAndBuffers->waveHandles );
  1629. handlesAndBuffers->waveHandles = 0;
  1630. }
  1631. if( handlesAndBuffers->bufferEvent )
  1632. {
  1633. result = CloseHandleWithPaError( handlesAndBuffers->bufferEvent );
  1634. handlesAndBuffers->bufferEvent = 0;
  1635. }
  1636. return result;
  1637. }
  1638. static PaError InitializeWaveHeaders( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers,
  1639. unsigned long hostBufferCount,
  1640. PaSampleFormat hostSampleFormat,
  1641. unsigned long framesPerHostBuffer,
  1642. PaWinMmeDeviceAndChannelCount *devices,
  1643. int isInput )
  1644. {
  1645. PaError result = paNoError;
  1646. MMRESULT mmresult;
  1647. WAVEHDR *deviceWaveHeaders;
  1648. signed int i, j;
  1649. /* for error cleanup we expect that InitializeSingleDirectionHandlesAndBuffers()
  1650. has already been called to zero some fields */
  1651. /* allocate an array of pointers to arrays of wave headers, one array of
  1652. wave headers per device */
  1653. handlesAndBuffers->waveHeaders = (WAVEHDR**)PaUtil_AllocateMemory( sizeof(WAVEHDR*) * handlesAndBuffers->deviceCount );
  1654. if( !handlesAndBuffers->waveHeaders )
  1655. {
  1656. result = paInsufficientMemory;
  1657. goto error;
  1658. }
  1659. for( i = 0; i < (signed int)handlesAndBuffers->deviceCount; ++i )
  1660. handlesAndBuffers->waveHeaders[i] = 0;
  1661. handlesAndBuffers->bufferCount = hostBufferCount;
  1662. for( i = 0; i < (signed int)handlesAndBuffers->deviceCount; ++i )
  1663. {
  1664. int bufferBytes = Pa_GetSampleSize( hostSampleFormat ) *
  1665. framesPerHostBuffer * devices[i].channelCount;
  1666. if( bufferBytes < 0 )
  1667. {
  1668. result = paInternalError;
  1669. goto error;
  1670. }
  1671. /* Allocate an array of wave headers for device i */
  1672. deviceWaveHeaders = (WAVEHDR *) PaUtil_AllocateMemory( sizeof(WAVEHDR)*hostBufferCount );
  1673. if( !deviceWaveHeaders )
  1674. {
  1675. result = paInsufficientMemory;
  1676. goto error;
  1677. }
  1678. for( j=0; j < (signed int)hostBufferCount; ++j )
  1679. deviceWaveHeaders[j].lpData = 0;
  1680. handlesAndBuffers->waveHeaders[i] = deviceWaveHeaders;
  1681. /* Allocate a buffer for each wave header */
  1682. for( j=0; j < (signed int)hostBufferCount; ++j )
  1683. {
  1684. deviceWaveHeaders[j].lpData = (char *)PaUtil_AllocateMemory( bufferBytes );
  1685. if( !deviceWaveHeaders[j].lpData )
  1686. {
  1687. result = paInsufficientMemory;
  1688. goto error;
  1689. }
  1690. deviceWaveHeaders[j].dwBufferLength = bufferBytes;
  1691. deviceWaveHeaders[j].dwUser = 0xFFFFFFFF; /* indicates that *PrepareHeader() has not yet been called, for error clean up code */
  1692. if( isInput )
  1693. {
  1694. mmresult = waveInPrepareHeader( ((HWAVEIN*)handlesAndBuffers->waveHandles)[i], &deviceWaveHeaders[j], sizeof(WAVEHDR) );
  1695. if( mmresult != MMSYSERR_NOERROR )
  1696. {
  1697. result = paUnanticipatedHostError;
  1698. PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
  1699. goto error;
  1700. }
  1701. }
  1702. else /* output */
  1703. {
  1704. mmresult = waveOutPrepareHeader( ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i], &deviceWaveHeaders[j], sizeof(WAVEHDR) );
  1705. if( mmresult != MMSYSERR_NOERROR )
  1706. {
  1707. result = paUnanticipatedHostError;
  1708. PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
  1709. goto error;
  1710. }
  1711. }
  1712. deviceWaveHeaders[j].dwUser = devices[i].channelCount;
  1713. }
  1714. }
  1715. return result;
  1716. error:
  1717. TerminateWaveHeaders( handlesAndBuffers, isInput );
  1718. return result;
  1719. }
  1720. static void TerminateWaveHeaders( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput )
  1721. {
  1722. signed int i, j;
  1723. WAVEHDR *deviceWaveHeaders;
  1724. if( handlesAndBuffers->waveHeaders )
  1725. {
  1726. for( i = handlesAndBuffers->deviceCount-1; i >= 0 ; --i )
  1727. {
  1728. deviceWaveHeaders = handlesAndBuffers->waveHeaders[i]; /* wave headers for device i */
  1729. if( deviceWaveHeaders )
  1730. {
  1731. for( j = handlesAndBuffers->bufferCount-1; j >= 0; --j )
  1732. {
  1733. if( deviceWaveHeaders[j].lpData )
  1734. {
  1735. if( deviceWaveHeaders[j].dwUser != 0xFFFFFFFF )
  1736. {
  1737. if( isInput )
  1738. waveInUnprepareHeader( ((HWAVEIN*)handlesAndBuffers->waveHandles)[i], &deviceWaveHeaders[j], sizeof(WAVEHDR) );
  1739. else
  1740. waveOutUnprepareHeader( ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i], &deviceWaveHeaders[j], sizeof(WAVEHDR) );
  1741. }
  1742. PaUtil_FreeMemory( deviceWaveHeaders[j].lpData );
  1743. }
  1744. }
  1745. PaUtil_FreeMemory( deviceWaveHeaders );
  1746. }
  1747. }
  1748. PaUtil_FreeMemory( handlesAndBuffers->waveHeaders );
  1749. handlesAndBuffers->waveHeaders = 0;
  1750. }
  1751. }
  1752. /* PaWinMmeStream - a stream data structure specifically for this implementation */
  1753. /* note that struct PaWinMmeStream is typedeffed to PaWinMmeStream above. */
  1754. struct PaWinMmeStream
  1755. {
  1756. PaUtilStreamRepresentation streamRepresentation;
  1757. PaUtilCpuLoadMeasurer cpuLoadMeasurer;
  1758. PaUtilBufferProcessor bufferProcessor;
  1759. int primeStreamUsingCallback;
  1760. PaWinMmeSingleDirectionHandlesAndBuffers input;
  1761. PaWinMmeSingleDirectionHandlesAndBuffers output;
  1762. /* Processing thread management -------------- */
  1763. HANDLE abortEvent;
  1764. HANDLE processingThread;
  1765. PA_THREAD_ID processingThreadId;
  1766. char throttleProcessingThreadOnOverload; /* 0 -> don't throtte, non-0 -> throttle */
  1767. int processingThreadPriority;
  1768. int highThreadPriority;
  1769. int throttledThreadPriority;
  1770. unsigned long throttledSleepMsecs;
  1771. int isStopped;
  1772. volatile int isActive;
  1773. volatile int stopProcessing; /* stop thread once existing buffers have been returned */
  1774. volatile int abortProcessing; /* stop thread immediately */
  1775. DWORD allBuffersDurationMs; /* used to calculate timeouts */
  1776. };
  1777. /* updates deviceCount if PaWinMmeUseMultipleDevices is used */
  1778. static PaError ValidateWinMmeSpecificStreamInfo(
  1779. const PaStreamParameters *streamParameters,
  1780. const PaWinMmeStreamInfo *streamInfo,
  1781. unsigned long *winMmeSpecificFlags,
  1782. char *throttleProcessingThreadOnOverload,
  1783. unsigned long *deviceCount )
  1784. {
  1785. if( streamInfo )
  1786. {
  1787. if( streamInfo->size != sizeof( PaWinMmeStreamInfo )
  1788. || streamInfo->version != 1 )
  1789. {
  1790. return paIncompatibleHostApiSpecificStreamInfo;
  1791. }
  1792. *winMmeSpecificFlags = streamInfo->flags;
  1793. if( streamInfo->flags & paWinMmeDontThrottleOverloadedProcessingThread )
  1794. *throttleProcessingThreadOnOverload = 0;
  1795. if( streamInfo->flags & paWinMmeUseMultipleDevices )
  1796. {
  1797. if( streamParameters->device != paUseHostApiSpecificDeviceSpecification )
  1798. return paInvalidDevice;
  1799. *deviceCount = streamInfo->deviceCount;
  1800. }
  1801. }
  1802. return paNoError;
  1803. }
  1804. static PaError RetrieveDevicesFromStreamParameters(
  1805. struct PaUtilHostApiRepresentation *hostApi,
  1806. const PaStreamParameters *streamParameters,
  1807. const PaWinMmeStreamInfo *streamInfo,
  1808. PaWinMmeDeviceAndChannelCount *devices,
  1809. unsigned long deviceCount )
  1810. {
  1811. PaError result = paNoError;
  1812. unsigned int i;
  1813. int totalChannelCount;
  1814. PaDeviceIndex hostApiDevice;
  1815. if( streamInfo && streamInfo->flags & paWinMmeUseMultipleDevices )
  1816. {
  1817. totalChannelCount = 0;
  1818. for( i=0; i < deviceCount; ++i )
  1819. {
  1820. /* validate that the device number is within range */
  1821. result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice,
  1822. streamInfo->devices[i].device, hostApi );
  1823. if( result != paNoError )
  1824. return result;
  1825. devices[i].device = hostApiDevice;
  1826. devices[i].channelCount = streamInfo->devices[i].channelCount;
  1827. totalChannelCount += devices[i].channelCount;
  1828. }
  1829. if( totalChannelCount != streamParameters->channelCount )
  1830. {
  1831. /* channelCount must match total channels specified by multiple devices */
  1832. return paInvalidChannelCount; /* REVIEW use of this error code */
  1833. }
  1834. }
  1835. else
  1836. {
  1837. devices[0].device = streamParameters->device;
  1838. devices[0].channelCount = streamParameters->channelCount;
  1839. }
  1840. return result;
  1841. }
  1842. static PaError ValidateInputChannelCounts(
  1843. struct PaUtilHostApiRepresentation *hostApi,
  1844. PaWinMmeDeviceAndChannelCount *devices,
  1845. unsigned long deviceCount )
  1846. {
  1847. unsigned int i;
  1848. PaWinMmeDeviceInfo *inputDeviceInfo;
  1849. PaError paerror;
  1850. for( i=0; i < deviceCount; ++i )
  1851. {
  1852. if( devices[i].channelCount < 1 )
  1853. return paInvalidChannelCount;
  1854. inputDeviceInfo =
  1855. (PaWinMmeDeviceInfo*)hostApi->deviceInfos[ devices[i].device ];
  1856. paerror = IsInputChannelCountSupported( inputDeviceInfo, devices[i].channelCount );
  1857. if( paerror != paNoError )
  1858. return paerror;
  1859. }
  1860. return paNoError;
  1861. }
  1862. static PaError ValidateOutputChannelCounts(
  1863. struct PaUtilHostApiRepresentation *hostApi,
  1864. PaWinMmeDeviceAndChannelCount *devices,
  1865. unsigned long deviceCount )
  1866. {
  1867. unsigned int i;
  1868. PaWinMmeDeviceInfo *outputDeviceInfo;
  1869. PaError paerror;
  1870. for( i=0; i < deviceCount; ++i )
  1871. {
  1872. if( devices[i].channelCount < 1 )
  1873. return paInvalidChannelCount;
  1874. outputDeviceInfo =
  1875. (PaWinMmeDeviceInfo*)hostApi->deviceInfos[ devices[i].device ];
  1876. paerror = IsOutputChannelCountSupported( outputDeviceInfo, devices[i].channelCount );
  1877. if( paerror != paNoError )
  1878. return paerror;
  1879. }
  1880. return paNoError;
  1881. }
  1882. /* the following macros are intended to improve the readability of the following code */
  1883. #define PA_IS_INPUT_STREAM_( stream ) ( stream ->input.waveHandles )
  1884. #define PA_IS_OUTPUT_STREAM_( stream ) ( stream ->output.waveHandles )
  1885. #define PA_IS_FULL_DUPLEX_STREAM_( stream ) ( stream ->input.waveHandles && stream ->output.waveHandles )
  1886. #define PA_IS_HALF_DUPLEX_STREAM_( stream ) ( !(stream ->input.waveHandles && stream ->output.waveHandles) )
  1887. static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
  1888. PaStream** s,
  1889. const PaStreamParameters *inputParameters,
  1890. const PaStreamParameters *outputParameters,
  1891. double sampleRate,
  1892. unsigned long framesPerBuffer,
  1893. PaStreamFlags streamFlags,
  1894. PaStreamCallback *streamCallback,
  1895. void *userData )
  1896. {
  1897. PaError result;
  1898. PaWinMmeHostApiRepresentation *winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi;
  1899. PaWinMmeStream *stream = 0;
  1900. int bufferProcessorIsInitialized = 0;
  1901. int streamRepresentationIsInitialized = 0;
  1902. PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
  1903. int inputChannelCount, outputChannelCount;
  1904. PaSampleFormat inputSampleFormat, outputSampleFormat;
  1905. double suggestedInputLatency, suggestedOutputLatency;
  1906. PaWinMmeStreamInfo *inputStreamInfo, *outputStreamInfo;
  1907. PaWinWaveFormatChannelMask inputChannelMask, outputChannelMask;
  1908. unsigned long framesPerHostInputBuffer;
  1909. unsigned long hostInputBufferCount;
  1910. unsigned long framesPerHostOutputBuffer;
  1911. unsigned long hostOutputBufferCount;
  1912. unsigned long framesPerBufferProcessorCall;
  1913. PaWinMmeDeviceAndChannelCount *inputDevices = 0; /* contains all devices and channel counts as local host api ids, even when PaWinMmeUseMultipleDevices is not used */
  1914. unsigned long winMmeSpecificInputFlags = 0;
  1915. unsigned long inputDeviceCount = 0;
  1916. PaWinMmeDeviceAndChannelCount *outputDevices = 0;
  1917. unsigned long winMmeSpecificOutputFlags = 0;
  1918. unsigned long outputDeviceCount = 0; /* contains all devices and channel counts as local host api ids, even when PaWinMmeUseMultipleDevices is not used */
  1919. char throttleProcessingThreadOnOverload = 1;
  1920. if( inputParameters )
  1921. {
  1922. inputChannelCount = inputParameters->channelCount;
  1923. inputSampleFormat = inputParameters->sampleFormat;
  1924. suggestedInputLatency = inputParameters->suggestedLatency;
  1925. inputDeviceCount = 1;
  1926. /* validate input hostApiSpecificStreamInfo */
  1927. inputStreamInfo = (PaWinMmeStreamInfo*)inputParameters->hostApiSpecificStreamInfo;
  1928. result = ValidateWinMmeSpecificStreamInfo( inputParameters, inputStreamInfo,
  1929. &winMmeSpecificInputFlags,
  1930. &throttleProcessingThreadOnOverload,
  1931. &inputDeviceCount );
  1932. if( result != paNoError ) return result;
  1933. inputDevices = (PaWinMmeDeviceAndChannelCount*)alloca( sizeof(PaWinMmeDeviceAndChannelCount) * inputDeviceCount );
  1934. if( !inputDevices ) return paInsufficientMemory;
  1935. result = RetrieveDevicesFromStreamParameters( hostApi, inputParameters, inputStreamInfo, inputDevices, inputDeviceCount );
  1936. if( result != paNoError ) return result;
  1937. result = ValidateInputChannelCounts( hostApi, inputDevices, inputDeviceCount );
  1938. if( result != paNoError ) return result;
  1939. hostInputSampleFormat =
  1940. PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, inputSampleFormat );
  1941. if( inputDeviceCount != 1 ){
  1942. /* always use direct speakers when using multi-device multichannel mode */
  1943. inputChannelMask = PAWIN_SPEAKER_DIRECTOUT;
  1944. }
  1945. else
  1946. {
  1947. if( inputStreamInfo && inputStreamInfo->flags & paWinMmeUseChannelMask )
  1948. inputChannelMask = inputStreamInfo->channelMask;
  1949. else
  1950. inputChannelMask = PaWin_DefaultChannelMask( inputDevices[0].channelCount );
  1951. }
  1952. }
  1953. else
  1954. {
  1955. inputChannelCount = 0;
  1956. inputSampleFormat = 0;
  1957. suggestedInputLatency = 0.;
  1958. inputStreamInfo = 0;
  1959. hostInputSampleFormat = 0;
  1960. }
  1961. if( outputParameters )
  1962. {
  1963. outputChannelCount = outputParameters->channelCount;
  1964. outputSampleFormat = outputParameters->sampleFormat;
  1965. suggestedOutputLatency = outputParameters->suggestedLatency;
  1966. outputDeviceCount = 1;
  1967. /* validate output hostApiSpecificStreamInfo */
  1968. outputStreamInfo = (PaWinMmeStreamInfo*)outputParameters->hostApiSpecificStreamInfo;
  1969. result = ValidateWinMmeSpecificStreamInfo( outputParameters, outputStreamInfo,
  1970. &winMmeSpecificOutputFlags,
  1971. &throttleProcessingThreadOnOverload,
  1972. &outputDeviceCount );
  1973. if( result != paNoError ) return result;
  1974. outputDevices = (PaWinMmeDeviceAndChannelCount*)alloca( sizeof(PaWinMmeDeviceAndChannelCount) * outputDeviceCount );
  1975. if( !outputDevices ) return paInsufficientMemory;
  1976. result = RetrieveDevicesFromStreamParameters( hostApi, outputParameters, outputStreamInfo, outputDevices, outputDeviceCount );
  1977. if( result != paNoError ) return result;
  1978. result = ValidateOutputChannelCounts( hostApi, outputDevices, outputDeviceCount );
  1979. if( result != paNoError ) return result;
  1980. hostOutputSampleFormat =
  1981. PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, outputSampleFormat );
  1982. if( outputDeviceCount != 1 ){
  1983. /* always use direct speakers when using multi-device multichannel mode */
  1984. outputChannelMask = PAWIN_SPEAKER_DIRECTOUT;
  1985. }
  1986. else
  1987. {
  1988. if( outputStreamInfo && outputStreamInfo->flags & paWinMmeUseChannelMask )
  1989. outputChannelMask = outputStreamInfo->channelMask;
  1990. else
  1991. outputChannelMask = PaWin_DefaultChannelMask( outputDevices[0].channelCount );
  1992. }
  1993. }
  1994. else
  1995. {
  1996. outputChannelCount = 0;
  1997. outputSampleFormat = 0;
  1998. outputStreamInfo = 0;
  1999. hostOutputSampleFormat = 0;
  2000. suggestedOutputLatency = 0.;
  2001. }
  2002. /*
  2003. IMPLEMENT ME:
  2004. - alter sampleRate to a close allowable rate if possible / necessary
  2005. */
  2006. /* validate platform specific flags */
  2007. if( (streamFlags & paPlatformSpecificFlags) != 0 )
  2008. return paInvalidFlag; /* unexpected platform specific flag */
  2009. /* always disable clipping and dithering if we are outputting a raw spdif stream */
  2010. if( (winMmeSpecificOutputFlags & paWinMmeWaveFormatDolbyAc3Spdif)
  2011. || (winMmeSpecificOutputFlags & paWinMmeWaveFormatWmaSpdif) ){
  2012. streamFlags = streamFlags | paClipOff | paDitherOff;
  2013. }
  2014. result = CalculateBufferSettings( &framesPerHostInputBuffer, &hostInputBufferCount,
  2015. &framesPerHostOutputBuffer, &hostOutputBufferCount,
  2016. inputChannelCount, hostInputSampleFormat, suggestedInputLatency, inputStreamInfo,
  2017. outputChannelCount, hostOutputSampleFormat, suggestedOutputLatency, outputStreamInfo,
  2018. sampleRate, framesPerBuffer );
  2019. if( result != paNoError ) goto error;
  2020. stream = (PaWinMmeStream*)PaUtil_AllocateMemory( sizeof(PaWinMmeStream) );
  2021. if( !stream )
  2022. {
  2023. result = paInsufficientMemory;
  2024. goto error;
  2025. }
  2026. InitializeSingleDirectionHandlesAndBuffers( &stream->input );
  2027. InitializeSingleDirectionHandlesAndBuffers( &stream->output );
  2028. stream->abortEvent = 0;
  2029. stream->processingThread = 0;
  2030. stream->throttleProcessingThreadOnOverload = throttleProcessingThreadOnOverload;
  2031. PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
  2032. ( (streamCallback)
  2033. ? &winMmeHostApi->callbackStreamInterface
  2034. : &winMmeHostApi->blockingStreamInterface ),
  2035. streamCallback, userData );
  2036. streamRepresentationIsInitialized = 1;
  2037. PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
  2038. if( inputParameters && outputParameters ) /* full duplex */
  2039. {
  2040. if( framesPerHostInputBuffer < framesPerHostOutputBuffer )
  2041. {
  2042. assert( (framesPerHostOutputBuffer % framesPerHostInputBuffer) == 0 ); /* CalculateBufferSettings() should guarantee this condition */
  2043. framesPerBufferProcessorCall = framesPerHostInputBuffer;
  2044. }
  2045. else
  2046. {
  2047. assert( (framesPerHostInputBuffer % framesPerHostOutputBuffer) == 0 ); /* CalculateBufferSettings() should guarantee this condition */
  2048. framesPerBufferProcessorCall = framesPerHostOutputBuffer;
  2049. }
  2050. }
  2051. else if( inputParameters )
  2052. {
  2053. framesPerBufferProcessorCall = framesPerHostInputBuffer;
  2054. }
  2055. else if( outputParameters )
  2056. {
  2057. framesPerBufferProcessorCall = framesPerHostOutputBuffer;
  2058. }
  2059. stream->input.framesPerBuffer = framesPerHostInputBuffer;
  2060. stream->output.framesPerBuffer = framesPerHostOutputBuffer;
  2061. result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
  2062. inputChannelCount, inputSampleFormat, hostInputSampleFormat,
  2063. outputChannelCount, outputSampleFormat, hostOutputSampleFormat,
  2064. sampleRate, streamFlags, framesPerBuffer,
  2065. framesPerBufferProcessorCall, paUtilFixedHostBufferSize,
  2066. streamCallback, userData );
  2067. if( result != paNoError ) goto error;
  2068. bufferProcessorIsInitialized = 1;
  2069. /* stream info input latency is the minimum buffering latency (unlike suggested and default which are *maximums*) */
  2070. stream->streamRepresentation.streamInfo.inputLatency =
  2071. (double)(PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor)
  2072. + framesPerHostInputBuffer) / sampleRate;
  2073. stream->streamRepresentation.streamInfo.outputLatency =
  2074. (double)(PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor)
  2075. + (framesPerHostOutputBuffer * (hostOutputBufferCount-1))) / sampleRate;
  2076. stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
  2077. stream->primeStreamUsingCallback = ( (streamFlags&paPrimeOutputBuffersUsingStreamCallback) && streamCallback ) ? 1 : 0;
  2078. /* time to sleep when throttling due to >100% cpu usage.
  2079. -a quater of a buffer's duration */
  2080. stream->throttledSleepMsecs =
  2081. (unsigned long)(stream->bufferProcessor.framesPerHostBuffer *
  2082. stream->bufferProcessor.samplePeriod * .25 * 1000);
  2083. stream->isStopped = 1;
  2084. stream->isActive = 0;
  2085. /* for maximum compatibility with multi-device multichannel drivers,
  2086. we first open all devices, then we prepare all buffers, finally
  2087. we start all devices ( in StartStream() ). teardown in reverse order.
  2088. */
  2089. if( inputParameters )
  2090. {
  2091. result = InitializeWaveHandles( winMmeHostApi, &stream->input,
  2092. winMmeSpecificInputFlags,
  2093. stream->bufferProcessor.bytesPerHostInputSample, sampleRate,
  2094. inputDevices, inputDeviceCount, inputChannelMask, 1 /* isInput */ );
  2095. if( result != paNoError ) goto error;
  2096. }
  2097. if( outputParameters )
  2098. {
  2099. result = InitializeWaveHandles( winMmeHostApi, &stream->output,
  2100. winMmeSpecificOutputFlags,
  2101. stream->bufferProcessor.bytesPerHostOutputSample, sampleRate,
  2102. outputDevices, outputDeviceCount, outputChannelMask, 0 /* isInput */ );
  2103. if( result != paNoError ) goto error;
  2104. }
  2105. if( inputParameters )
  2106. {
  2107. result = InitializeWaveHeaders( &stream->input, hostInputBufferCount,
  2108. hostInputSampleFormat, framesPerHostInputBuffer, inputDevices, 1 /* isInput */ );
  2109. if( result != paNoError ) goto error;
  2110. }
  2111. if( outputParameters )
  2112. {
  2113. result = InitializeWaveHeaders( &stream->output, hostOutputBufferCount,
  2114. hostOutputSampleFormat, framesPerHostOutputBuffer, outputDevices, 0 /* not isInput */ );
  2115. if( result != paNoError ) goto error;
  2116. stream->allBuffersDurationMs = (DWORD) (1000.0 * (framesPerHostOutputBuffer * stream->output.bufferCount) / sampleRate);
  2117. }
  2118. else
  2119. {
  2120. stream->allBuffersDurationMs = (DWORD) (1000.0 * (framesPerHostInputBuffer * stream->input.bufferCount) / sampleRate);
  2121. }
  2122. if( streamCallback )
  2123. {
  2124. /* abort event is only needed for callback streams */
  2125. result = CreateEventWithPaError( &stream->abortEvent, NULL, TRUE, FALSE, NULL );
  2126. if( result != paNoError ) goto error;
  2127. }
  2128. *s = (PaStream*)stream;
  2129. return result;
  2130. error:
  2131. if( stream )
  2132. {
  2133. if( stream->abortEvent )
  2134. CloseHandle( stream->abortEvent );
  2135. TerminateWaveHeaders( &stream->output, 0 /* not isInput */ );
  2136. TerminateWaveHeaders( &stream->input, 1 /* isInput */ );
  2137. TerminateWaveHandles( &stream->output, 0 /* not isInput */, 1 /* currentlyProcessingAnError */ );
  2138. TerminateWaveHandles( &stream->input, 1 /* isInput */, 1 /* currentlyProcessingAnError */ );
  2139. if( bufferProcessorIsInitialized )
  2140. PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
  2141. if( streamRepresentationIsInitialized )
  2142. PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
  2143. PaUtil_FreeMemory( stream );
  2144. }
  2145. return result;
  2146. }
  2147. /* return non-zero if all current buffers are done */
  2148. static int BuffersAreDone( WAVEHDR **waveHeaders, unsigned int deviceCount, int bufferIndex )
  2149. {
  2150. unsigned int i;
  2151. for( i=0; i < deviceCount; ++i )
  2152. {
  2153. if( !(waveHeaders[i][ bufferIndex ].dwFlags & WHDR_DONE) )
  2154. {
  2155. return 0;
  2156. }
  2157. }
  2158. return 1;
  2159. }
  2160. static int CurrentInputBuffersAreDone( PaWinMmeStream *stream )
  2161. {
  2162. return BuffersAreDone( stream->input.waveHeaders, stream->input.deviceCount, stream->input.currentBufferIndex );
  2163. }
  2164. static int CurrentOutputBuffersAreDone( PaWinMmeStream *stream )
  2165. {
  2166. return BuffersAreDone( stream->output.waveHeaders, stream->output.deviceCount, stream->output.currentBufferIndex );
  2167. }
  2168. /* return non-zero if any buffers are queued */
  2169. static int NoBuffersAreQueued( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers )
  2170. {
  2171. unsigned int i, j;
  2172. if( handlesAndBuffers->waveHandles )
  2173. {
  2174. for( i=0; i < handlesAndBuffers->bufferCount; ++i )
  2175. {
  2176. for( j=0; j < handlesAndBuffers->deviceCount; ++j )
  2177. {
  2178. if( !( handlesAndBuffers->waveHeaders[ j ][ i ].dwFlags & WHDR_DONE) )
  2179. {
  2180. return 0;
  2181. }
  2182. }
  2183. }
  2184. }
  2185. return 1;
  2186. }
  2187. #define PA_CIRCULAR_INCREMENT_( current, max )\
  2188. ( (((current) + 1) >= (max)) ? (0) : (current+1) )
  2189. #define PA_CIRCULAR_DECREMENT_( current, max )\
  2190. ( ((current) == 0) ? ((max)-1) : (current-1) )
  2191. static signed long GetAvailableFrames( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers )
  2192. {
  2193. signed long result = 0;
  2194. unsigned int i;
  2195. if( BuffersAreDone( handlesAndBuffers->waveHeaders, handlesAndBuffers->deviceCount, handlesAndBuffers->currentBufferIndex ) )
  2196. {
  2197. /* we could calculate the following in O(1) if we kept track of the
  2198. last done buffer */
  2199. result = handlesAndBuffers->framesPerBuffer - handlesAndBuffers->framesUsedInCurrentBuffer;
  2200. i = PA_CIRCULAR_INCREMENT_( handlesAndBuffers->currentBufferIndex, handlesAndBuffers->bufferCount );
  2201. while( i != handlesAndBuffers->currentBufferIndex )
  2202. {
  2203. if( BuffersAreDone( handlesAndBuffers->waveHeaders, handlesAndBuffers->deviceCount, i ) )
  2204. {
  2205. result += handlesAndBuffers->framesPerBuffer;
  2206. i = PA_CIRCULAR_INCREMENT_( i, handlesAndBuffers->bufferCount );
  2207. }
  2208. else
  2209. break;
  2210. }
  2211. }
  2212. return result;
  2213. }
  2214. static PaError AdvanceToNextInputBuffer( PaWinMmeStream *stream )
  2215. {
  2216. PaError result = paNoError;
  2217. MMRESULT mmresult;
  2218. unsigned int i;
  2219. for( i=0; i < stream->input.deviceCount; ++i )
  2220. {
  2221. stream->input.waveHeaders[i][ stream->input.currentBufferIndex ].dwFlags &= ~WHDR_DONE;
  2222. mmresult = waveInAddBuffer( ((HWAVEIN*)stream->input.waveHandles)[i],
  2223. &stream->input.waveHeaders[i][ stream->input.currentBufferIndex ],
  2224. sizeof(WAVEHDR) );
  2225. if( mmresult != MMSYSERR_NOERROR )
  2226. {
  2227. result = paUnanticipatedHostError;
  2228. PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
  2229. }
  2230. }
  2231. stream->input.currentBufferIndex =
  2232. PA_CIRCULAR_INCREMENT_( stream->input.currentBufferIndex, stream->input.bufferCount );
  2233. stream->input.framesUsedInCurrentBuffer = 0;
  2234. return result;
  2235. }
  2236. static PaError AdvanceToNextOutputBuffer( PaWinMmeStream *stream )
  2237. {
  2238. PaError result = paNoError;
  2239. MMRESULT mmresult;
  2240. unsigned int i;
  2241. for( i=0; i < stream->output.deviceCount; ++i )
  2242. {
  2243. mmresult = waveOutWrite( ((HWAVEOUT*)stream->output.waveHandles)[i],
  2244. &stream->output.waveHeaders[i][ stream->output.currentBufferIndex ],
  2245. sizeof(WAVEHDR) );
  2246. if( mmresult != MMSYSERR_NOERROR )
  2247. {
  2248. result = paUnanticipatedHostError;
  2249. PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
  2250. }
  2251. }
  2252. stream->output.currentBufferIndex =
  2253. PA_CIRCULAR_INCREMENT_( stream->output.currentBufferIndex, stream->output.bufferCount );
  2254. stream->output.framesUsedInCurrentBuffer = 0;
  2255. return result;
  2256. }
  2257. /* requeue all but the most recent input with the driver. Used for catching
  2258. up after a total input buffer underrun */
  2259. static PaError CatchUpInputBuffers( PaWinMmeStream *stream )
  2260. {
  2261. PaError result = paNoError;
  2262. unsigned int i;
  2263. for( i=0; i < stream->input.bufferCount - 1; ++i )
  2264. {
  2265. result = AdvanceToNextInputBuffer( stream );
  2266. if( result != paNoError )
  2267. break;
  2268. }
  2269. return result;
  2270. }
  2271. /* take the most recent output and duplicate it to all other output buffers
  2272. and requeue them. Used for catching up after a total output buffer underrun.
  2273. */
  2274. static PaError CatchUpOutputBuffers( PaWinMmeStream *stream )
  2275. {
  2276. PaError result = paNoError;
  2277. unsigned int i, j;
  2278. unsigned int previousBufferIndex =
  2279. PA_CIRCULAR_DECREMENT_( stream->output.currentBufferIndex, stream->output.bufferCount );
  2280. for( i=0; i < stream->output.bufferCount - 1; ++i )
  2281. {
  2282. for( j=0; j < stream->output.deviceCount; ++j )
  2283. {
  2284. if( stream->output.waveHeaders[j][ stream->output.currentBufferIndex ].lpData
  2285. != stream->output.waveHeaders[j][ previousBufferIndex ].lpData )
  2286. {
  2287. CopyMemory( stream->output.waveHeaders[j][ stream->output.currentBufferIndex ].lpData,
  2288. stream->output.waveHeaders[j][ previousBufferIndex ].lpData,
  2289. stream->output.waveHeaders[j][ stream->output.currentBufferIndex ].dwBufferLength );
  2290. }
  2291. }
  2292. result = AdvanceToNextOutputBuffer( stream );
  2293. if( result != paNoError )
  2294. break;
  2295. }
  2296. return result;
  2297. }
  2298. PA_THREAD_FUNC ProcessingThreadProc( void *pArg )
  2299. {
  2300. PaWinMmeStream *stream = (PaWinMmeStream *)pArg;
  2301. HANDLE events[3];
  2302. int eventCount = 0;
  2303. DWORD result = paNoError;
  2304. DWORD waitResult;
  2305. DWORD timeout = (unsigned long)(stream->allBuffersDurationMs * 0.5);
  2306. int hostBuffersAvailable;
  2307. signed int hostInputBufferIndex, hostOutputBufferIndex;
  2308. PaStreamCallbackFlags statusFlags;
  2309. int callbackResult;
  2310. int done = 0;
  2311. unsigned int channel, i;
  2312. unsigned long framesProcessed;
  2313. /* prepare event array for call to WaitForMultipleObjects() */
  2314. if( stream->input.bufferEvent )
  2315. events[eventCount++] = stream->input.bufferEvent;
  2316. if( stream->output.bufferEvent )
  2317. events[eventCount++] = stream->output.bufferEvent;
  2318. events[eventCount++] = stream->abortEvent;
  2319. statusFlags = 0; /** @todo support paInputUnderflow, paOutputOverflow and paNeverDropInput */
  2320. /* loop until something causes us to stop */
  2321. do{
  2322. /* wait for MME to signal that a buffer is available, or for
  2323. the PA abort event to be signaled.
  2324. When this indicates that one or more buffers are available
  2325. NoBuffersAreQueued() and Current*BuffersAreDone are used below to
  2326. poll for additional done buffers. NoBuffersAreQueued() will fail
  2327. to identify an underrun/overflow if the driver doesn't mark all done
  2328. buffers prior to signalling the event. Some drivers do this
  2329. (eg RME Digi96, and others don't eg VIA PC 97 input). This isn't a
  2330. huge problem, it just means that we won't always be able to detect
  2331. underflow/overflow.
  2332. */
  2333. waitResult = WaitForMultipleObjects( eventCount, events, FALSE /* wait all = FALSE */, timeout );
  2334. if( waitResult == WAIT_FAILED )
  2335. {
  2336. result = paUnanticipatedHostError;
  2337. /** @todo FIXME/REVIEW: can't return host error info from an asyncronous thread. see http://www.portaudio.com/trac/ticket/143 */
  2338. done = 1;
  2339. }
  2340. else if( waitResult == WAIT_TIMEOUT )
  2341. {
  2342. /* if a timeout is encountered, continue */
  2343. }
  2344. if( stream->abortProcessing )
  2345. {
  2346. /* Pa_AbortStream() has been called, stop processing immediately */
  2347. done = 1;
  2348. }
  2349. else if( stream->stopProcessing )
  2350. {
  2351. /* Pa_StopStream() has been called or the user callback returned
  2352. non-zero, processing will continue until all output buffers
  2353. are marked as done. The stream will stop immediately if it
  2354. is input-only.
  2355. */
  2356. if( PA_IS_OUTPUT_STREAM_(stream) )
  2357. {
  2358. if( NoBuffersAreQueued( &stream->output ) )
  2359. done = 1; /* Will cause thread to return. */
  2360. }
  2361. else
  2362. {
  2363. /* input only stream */
  2364. done = 1; /* Will cause thread to return. */
  2365. }
  2366. }
  2367. else
  2368. {
  2369. hostBuffersAvailable = 1;
  2370. /* process all available host buffers */
  2371. do
  2372. {
  2373. hostInputBufferIndex = -1;
  2374. hostOutputBufferIndex = -1;
  2375. if( PA_IS_INPUT_STREAM_(stream) )
  2376. {
  2377. if( CurrentInputBuffersAreDone( stream ) )
  2378. {
  2379. if( NoBuffersAreQueued( &stream->input ) )
  2380. {
  2381. /** @todo
  2382. if all of the other buffers are also ready then
  2383. we discard all but the most recent. This is an
  2384. input buffer overflow. FIXME: these buffers should
  2385. be passed to the callback in a paNeverDropInput
  2386. stream. http://www.portaudio.com/trac/ticket/142
  2387. note that it is also possible for an input overflow
  2388. to happen while the callback is processing a buffer.
  2389. that is handled further down.
  2390. */
  2391. result = CatchUpInputBuffers( stream );
  2392. if( result != paNoError )
  2393. done = 1;
  2394. statusFlags |= paInputOverflow;
  2395. }
  2396. hostInputBufferIndex = stream->input.currentBufferIndex;
  2397. }
  2398. }
  2399. if( PA_IS_OUTPUT_STREAM_(stream) )
  2400. {
  2401. if( CurrentOutputBuffersAreDone( stream ) )
  2402. {
  2403. /* ok, we have an output buffer */
  2404. if( NoBuffersAreQueued( &stream->output ) )
  2405. {
  2406. /*
  2407. if all of the other buffers are also ready, catch up by copying
  2408. the most recently generated buffer into all but one of the output
  2409. buffers.
  2410. note that this catch up code only handles the case where all
  2411. buffers have been played out due to this thread not having
  2412. woken up at all. a more common case occurs when this thread
  2413. is woken up, processes one buffer, but takes too long, and as
  2414. a result all the other buffers have become un-queued. that
  2415. case is handled further down.
  2416. */
  2417. result = CatchUpOutputBuffers( stream );
  2418. if( result != paNoError )
  2419. done = 1;
  2420. statusFlags |= paOutputUnderflow;
  2421. }
  2422. hostOutputBufferIndex = stream->output.currentBufferIndex;
  2423. }
  2424. }
  2425. if( (PA_IS_FULL_DUPLEX_STREAM_(stream) && hostInputBufferIndex != -1 && hostOutputBufferIndex != -1) ||
  2426. (PA_IS_HALF_DUPLEX_STREAM_(stream) && ( hostInputBufferIndex != -1 || hostOutputBufferIndex != -1 ) ) )
  2427. {
  2428. PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /** @todo implement inputBufferAdcTime */
  2429. if( PA_IS_OUTPUT_STREAM_(stream) )
  2430. {
  2431. /* set timeInfo.currentTime and calculate timeInfo.outputBufferDacTime
  2432. from the current wave out position */
  2433. MMTIME mmtime;
  2434. double timeBeforeGetPosition, timeAfterGetPosition;
  2435. double time;
  2436. long framesInBufferRing;
  2437. long writePosition;
  2438. long playbackPosition;
  2439. HWAVEOUT firstWaveOutDevice = ((HWAVEOUT*)stream->output.waveHandles)[0];
  2440. mmtime.wType = TIME_SAMPLES;
  2441. timeBeforeGetPosition = PaUtil_GetTime();
  2442. waveOutGetPosition( firstWaveOutDevice, &mmtime, sizeof(MMTIME) );
  2443. timeAfterGetPosition = PaUtil_GetTime();
  2444. timeInfo.currentTime = timeAfterGetPosition;
  2445. /* approximate time at which wave out position was measured
  2446. as half way between timeBeforeGetPosition and timeAfterGetPosition */
  2447. time = timeBeforeGetPosition + (timeAfterGetPosition - timeBeforeGetPosition) * .5;
  2448. framesInBufferRing = stream->output.bufferCount * stream->bufferProcessor.framesPerHostBuffer;
  2449. playbackPosition = mmtime.u.sample % framesInBufferRing;
  2450. writePosition = stream->output.currentBufferIndex * stream->bufferProcessor.framesPerHostBuffer
  2451. + stream->output.framesUsedInCurrentBuffer;
  2452. if( playbackPosition >= writePosition ){
  2453. timeInfo.outputBufferDacTime =
  2454. time + ((double)( writePosition + (framesInBufferRing - playbackPosition) ) * stream->bufferProcessor.samplePeriod );
  2455. }else{
  2456. timeInfo.outputBufferDacTime =
  2457. time + ((double)( writePosition - playbackPosition ) * stream->bufferProcessor.samplePeriod );
  2458. }
  2459. }
  2460. PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
  2461. PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, statusFlags );
  2462. /* reset status flags once they have been passed to the buffer processor */
  2463. statusFlags = 0;
  2464. if( PA_IS_INPUT_STREAM_(stream) )
  2465. {
  2466. PaUtil_SetInputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
  2467. channel = 0;
  2468. for( i=0; i<stream->input.deviceCount; ++i )
  2469. {
  2470. /* we have stored the number of channels in the buffer in dwUser */
  2471. int channelCount = (int)stream->input.waveHeaders[i][ hostInputBufferIndex ].dwUser;
  2472. PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, channel,
  2473. stream->input.waveHeaders[i][ hostInputBufferIndex ].lpData +
  2474. stream->input.framesUsedInCurrentBuffer * channelCount *
  2475. stream->bufferProcessor.bytesPerHostInputSample,
  2476. channelCount );
  2477. channel += channelCount;
  2478. }
  2479. }
  2480. if( PA_IS_OUTPUT_STREAM_(stream) )
  2481. {
  2482. PaUtil_SetOutputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
  2483. channel = 0;
  2484. for( i=0; i<stream->output.deviceCount; ++i )
  2485. {
  2486. /* we have stored the number of channels in the buffer in dwUser */
  2487. int channelCount = (int)stream->output.waveHeaders[i][ hostOutputBufferIndex ].dwUser;
  2488. PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, channel,
  2489. stream->output.waveHeaders[i][ hostOutputBufferIndex ].lpData +
  2490. stream->output.framesUsedInCurrentBuffer * channelCount *
  2491. stream->bufferProcessor.bytesPerHostOutputSample,
  2492. channelCount );
  2493. channel += channelCount;
  2494. }
  2495. }
  2496. callbackResult = paContinue;
  2497. framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );
  2498. stream->input.framesUsedInCurrentBuffer += framesProcessed;
  2499. stream->output.framesUsedInCurrentBuffer += framesProcessed;
  2500. PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
  2501. if( callbackResult == paContinue )
  2502. {
  2503. /* nothing special to do */
  2504. }
  2505. else if( callbackResult == paAbort )
  2506. {
  2507. stream->abortProcessing = 1;
  2508. done = 1;
  2509. /** @todo FIXME: should probably reset the output device immediately once the callback returns paAbort
  2510. see: http://www.portaudio.com/trac/ticket/141
  2511. */
  2512. result = paNoError;
  2513. }
  2514. else
  2515. {
  2516. /* User callback has asked us to stop with paComplete or other non-zero value */
  2517. stream->stopProcessing = 1; /* stop once currently queued audio has finished */
  2518. result = paNoError;
  2519. }
  2520. if( PA_IS_INPUT_STREAM_(stream)
  2521. && stream->stopProcessing == 0 && stream->abortProcessing == 0
  2522. && stream->input.framesUsedInCurrentBuffer == stream->input.framesPerBuffer )
  2523. {
  2524. if( NoBuffersAreQueued( &stream->input ) )
  2525. {
  2526. /** @todo need to handle PaNeverDropInput here where necessary */
  2527. result = CatchUpInputBuffers( stream );
  2528. if( result != paNoError )
  2529. done = 1;
  2530. statusFlags |= paInputOverflow;
  2531. }
  2532. result = AdvanceToNextInputBuffer( stream );
  2533. if( result != paNoError )
  2534. done = 1;
  2535. }
  2536. if( PA_IS_OUTPUT_STREAM_(stream) && !stream->abortProcessing )
  2537. {
  2538. if( stream->stopProcessing &&
  2539. stream->output.framesUsedInCurrentBuffer < stream->output.framesPerBuffer )
  2540. {
  2541. /* zero remaining samples in output output buffer and flush */
  2542. stream->output.framesUsedInCurrentBuffer += PaUtil_ZeroOutput( &stream->bufferProcessor,
  2543. stream->output.framesPerBuffer - stream->output.framesUsedInCurrentBuffer );
  2544. /* we send the entire buffer to the output devices, but we could
  2545. just send a partial buffer, rather than zeroing the unused
  2546. samples.
  2547. */
  2548. }
  2549. if( stream->output.framesUsedInCurrentBuffer == stream->output.framesPerBuffer )
  2550. {
  2551. /* check for underflow before enquing the just-generated buffer,
  2552. but recover from underflow after enquing it. This ensures
  2553. that the most recent audio segment is repeated */
  2554. int outputUnderflow = NoBuffersAreQueued( &stream->output );
  2555. result = AdvanceToNextOutputBuffer( stream );
  2556. if( result != paNoError )
  2557. done = 1;
  2558. if( outputUnderflow && !done && !stream->stopProcessing )
  2559. {
  2560. /* Recover from underflow in the case where the
  2561. underflow occured while processing the buffer
  2562. we just finished */
  2563. result = CatchUpOutputBuffers( stream );
  2564. if( result != paNoError )
  2565. done = 1;
  2566. statusFlags |= paOutputUnderflow;
  2567. }
  2568. }
  2569. }
  2570. if( stream->throttleProcessingThreadOnOverload != 0 )
  2571. {
  2572. if( stream->stopProcessing || stream->abortProcessing )
  2573. {
  2574. if( stream->processingThreadPriority != stream->highThreadPriority )
  2575. {
  2576. SetThreadPriority( stream->processingThread, stream->highThreadPriority );
  2577. stream->processingThreadPriority = stream->highThreadPriority;
  2578. }
  2579. }
  2580. else if( PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ) > 1. )
  2581. {
  2582. if( stream->processingThreadPriority != stream->throttledThreadPriority )
  2583. {
  2584. SetThreadPriority( stream->processingThread, stream->throttledThreadPriority );
  2585. stream->processingThreadPriority = stream->throttledThreadPriority;
  2586. }
  2587. /* sleep to give other processes a go */
  2588. Sleep( stream->throttledSleepMsecs );
  2589. }
  2590. else
  2591. {
  2592. if( stream->processingThreadPriority != stream->highThreadPriority )
  2593. {
  2594. SetThreadPriority( stream->processingThread, stream->highThreadPriority );
  2595. stream->processingThreadPriority = stream->highThreadPriority;
  2596. }
  2597. }
  2598. }
  2599. }
  2600. else
  2601. {
  2602. hostBuffersAvailable = 0;
  2603. }
  2604. }
  2605. while( hostBuffersAvailable &&
  2606. stream->stopProcessing == 0 &&
  2607. stream->abortProcessing == 0 &&
  2608. !done );
  2609. }
  2610. }
  2611. while( !done );
  2612. stream->isActive = 0;
  2613. if( stream->streamRepresentation.streamFinishedCallback != 0 )
  2614. stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
  2615. PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer );
  2616. return result;
  2617. }
  2618. /*
  2619. When CloseStream() is called, the multi-api layer ensures that
  2620. the stream has already been stopped or aborted.
  2621. */
  2622. static PaError CloseStream( PaStream* s )
  2623. {
  2624. PaError result;
  2625. PaWinMmeStream *stream = (PaWinMmeStream*)s;
  2626. result = CloseHandleWithPaError( stream->abortEvent );
  2627. if( result != paNoError ) goto error;
  2628. TerminateWaveHeaders( &stream->output, 0 /* not isInput */ );
  2629. TerminateWaveHeaders( &stream->input, 1 /* isInput */ );
  2630. TerminateWaveHandles( &stream->output, 0 /* not isInput */, 0 /* not currentlyProcessingAnError */ );
  2631. TerminateWaveHandles( &stream->input, 1 /* isInput */, 0 /* not currentlyProcessingAnError */ );
  2632. PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
  2633. PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
  2634. PaUtil_FreeMemory( stream );
  2635. error:
  2636. /** @todo REVIEW: what is the best way to clean up a stream if an error is detected? */
  2637. return result;
  2638. }
  2639. static PaError StartStream( PaStream *s )
  2640. {
  2641. PaError result;
  2642. PaWinMmeStream *stream = (PaWinMmeStream*)s;
  2643. MMRESULT mmresult;
  2644. unsigned int i, j;
  2645. int callbackResult;
  2646. unsigned int channel;
  2647. unsigned long framesProcessed;
  2648. PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /** @todo implement this for stream priming */
  2649. PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
  2650. if( PA_IS_INPUT_STREAM_(stream) )
  2651. {
  2652. for( i=0; i<stream->input.bufferCount; ++i )
  2653. {
  2654. for( j=0; j<stream->input.deviceCount; ++j )
  2655. {
  2656. stream->input.waveHeaders[j][i].dwFlags &= ~WHDR_DONE;
  2657. mmresult = waveInAddBuffer( ((HWAVEIN*)stream->input.waveHandles)[j], &stream->input.waveHeaders[j][i], sizeof(WAVEHDR) );
  2658. if( mmresult != MMSYSERR_NOERROR )
  2659. {
  2660. result = paUnanticipatedHostError;
  2661. PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
  2662. goto error;
  2663. }
  2664. }
  2665. }
  2666. stream->input.currentBufferIndex = 0;
  2667. stream->input.framesUsedInCurrentBuffer = 0;
  2668. }
  2669. if( PA_IS_OUTPUT_STREAM_(stream) )
  2670. {
  2671. for( i=0; i<stream->output.deviceCount; ++i )
  2672. {
  2673. if( (mmresult = waveOutPause( ((HWAVEOUT*)stream->output.waveHandles)[i] )) != MMSYSERR_NOERROR )
  2674. {
  2675. result = paUnanticipatedHostError;
  2676. PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
  2677. goto error;
  2678. }
  2679. }
  2680. for( i=0; i<stream->output.bufferCount; ++i )
  2681. {
  2682. if( stream->primeStreamUsingCallback )
  2683. {
  2684. stream->output.framesUsedInCurrentBuffer = 0;
  2685. do{
  2686. PaUtil_BeginBufferProcessing( &stream->bufferProcessor,
  2687. &timeInfo,
  2688. paPrimingOutput | ((stream->input.bufferCount > 0 ) ? paInputUnderflow : 0));
  2689. if( stream->input.bufferCount > 0 )
  2690. PaUtil_SetNoInput( &stream->bufferProcessor );
  2691. PaUtil_SetOutputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
  2692. channel = 0;
  2693. for( j=0; j<stream->output.deviceCount; ++j )
  2694. {
  2695. /* we have stored the number of channels in the buffer in dwUser */
  2696. int channelCount = (int)stream->output.waveHeaders[j][i].dwUser;
  2697. PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, channel,
  2698. stream->output.waveHeaders[j][i].lpData +
  2699. stream->output.framesUsedInCurrentBuffer * channelCount *
  2700. stream->bufferProcessor.bytesPerHostOutputSample,
  2701. channelCount );
  2702. /* we have stored the number of channels in the buffer in dwUser */
  2703. channel += channelCount;
  2704. }
  2705. callbackResult = paContinue;
  2706. framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );
  2707. stream->output.framesUsedInCurrentBuffer += framesProcessed;
  2708. if( callbackResult != paContinue )
  2709. {
  2710. /** @todo fix this, what do we do if callback result is non-zero during stream
  2711. priming?
  2712. for complete: play out primed waveHeaders as usual
  2713. for abort: clean up immediately.
  2714. */
  2715. }
  2716. }while( stream->output.framesUsedInCurrentBuffer != stream->output.framesPerBuffer );
  2717. }
  2718. else
  2719. {
  2720. for( j=0; j<stream->output.deviceCount; ++j )
  2721. {
  2722. ZeroMemory( stream->output.waveHeaders[j][i].lpData, stream->output.waveHeaders[j][i].dwBufferLength );
  2723. }
  2724. }
  2725. /* we queue all channels of a single buffer frame (accross all
  2726. devices, because some multidevice multichannel drivers work
  2727. better this way */
  2728. for( j=0; j<stream->output.deviceCount; ++j )
  2729. {
  2730. mmresult = waveOutWrite( ((HWAVEOUT*)stream->output.waveHandles)[j], &stream->output.waveHeaders[j][i], sizeof(WAVEHDR) );
  2731. if( mmresult != MMSYSERR_NOERROR )
  2732. {
  2733. result = paUnanticipatedHostError;
  2734. PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
  2735. goto error;
  2736. }
  2737. }
  2738. }
  2739. stream->output.currentBufferIndex = 0;
  2740. stream->output.framesUsedInCurrentBuffer = 0;
  2741. }
  2742. stream->isStopped = 0;
  2743. stream->isActive = 1;
  2744. stream->stopProcessing = 0;
  2745. stream->abortProcessing = 0;
  2746. result = ResetEventWithPaError( stream->input.bufferEvent );
  2747. if( result != paNoError ) goto error;
  2748. result = ResetEventWithPaError( stream->output.bufferEvent );
  2749. if( result != paNoError ) goto error;
  2750. if( stream->streamRepresentation.streamCallback )
  2751. {
  2752. /* callback stream */
  2753. result = ResetEventWithPaError( stream->abortEvent );
  2754. if( result != paNoError ) goto error;
  2755. /* Create thread that waits for audio buffers to be ready for processing. */
  2756. stream->processingThread = CREATE_THREAD;
  2757. if( !stream->processingThread )
  2758. {
  2759. result = paUnanticipatedHostError;
  2760. PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
  2761. goto error;
  2762. }
  2763. /** @todo could have mme specific stream parameters to allow the user
  2764. to set the callback thread priorities */
  2765. stream->highThreadPriority = THREAD_PRIORITY_TIME_CRITICAL;
  2766. stream->throttledThreadPriority = THREAD_PRIORITY_NORMAL;
  2767. if( !SetThreadPriority( stream->processingThread, stream->highThreadPriority ) )
  2768. {
  2769. result = paUnanticipatedHostError;
  2770. PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
  2771. goto error;
  2772. }
  2773. stream->processingThreadPriority = stream->highThreadPriority;
  2774. }
  2775. else
  2776. {
  2777. /* blocking read/write stream */
  2778. }
  2779. if( PA_IS_INPUT_STREAM_(stream) )
  2780. {
  2781. for( i=0; i < stream->input.deviceCount; ++i )
  2782. {
  2783. mmresult = waveInStart( ((HWAVEIN*)stream->input.waveHandles)[i] );
  2784. PA_DEBUG(("Pa_StartStream: waveInStart returned = 0x%X.\n", mmresult));
  2785. if( mmresult != MMSYSERR_NOERROR )
  2786. {
  2787. result = paUnanticipatedHostError;
  2788. PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
  2789. goto error;
  2790. }
  2791. }
  2792. }
  2793. if( PA_IS_OUTPUT_STREAM_(stream) )
  2794. {
  2795. for( i=0; i < stream->output.deviceCount; ++i )
  2796. {
  2797. if( (mmresult = waveOutRestart( ((HWAVEOUT*)stream->output.waveHandles)[i] )) != MMSYSERR_NOERROR )
  2798. {
  2799. result = paUnanticipatedHostError;
  2800. PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
  2801. goto error;
  2802. }
  2803. }
  2804. }
  2805. return result;
  2806. error:
  2807. /** @todo FIXME: implement recovery as best we can
  2808. This should involve rolling back to a state as-if this function had never been called
  2809. */
  2810. return result;
  2811. }
  2812. static PaError StopStream( PaStream *s )
  2813. {
  2814. PaError result = paNoError;
  2815. PaWinMmeStream *stream = (PaWinMmeStream*)s;
  2816. int timeout;
  2817. DWORD waitResult;
  2818. MMRESULT mmresult;
  2819. signed int hostOutputBufferIndex;
  2820. unsigned int channel, waitCount, i;
  2821. /** @todo
  2822. REVIEW: the error checking in this function needs review. the basic
  2823. idea is to return from this function in a known state - for example
  2824. there is no point avoiding calling waveInReset just because
  2825. the thread times out.
  2826. */
  2827. if( stream->processingThread )
  2828. {
  2829. /* callback stream */
  2830. /* Tell processing thread to stop generating more data and to let current data play out. */
  2831. stream->stopProcessing = 1;
  2832. /* Calculate timeOut longer than longest time it could take to return all buffers. */
  2833. timeout = (int)(stream->allBuffersDurationMs * 1.5);
  2834. if( timeout < PA_MME_MIN_TIMEOUT_MSEC_ )
  2835. timeout = PA_MME_MIN_TIMEOUT_MSEC_;
  2836. PA_DEBUG(("WinMME StopStream: waiting for background thread.\n"));
  2837. waitResult = WaitForSingleObject( stream->processingThread, timeout );
  2838. if( waitResult == WAIT_TIMEOUT )
  2839. {
  2840. /* try to abort */
  2841. stream->abortProcessing = 1;
  2842. SetEvent( stream->abortEvent );
  2843. waitResult = WaitForSingleObject( stream->processingThread, timeout );
  2844. if( waitResult == WAIT_TIMEOUT )
  2845. {
  2846. PA_DEBUG(("WinMME StopStream: timed out while waiting for background thread to finish.\n"));
  2847. result = paTimedOut;
  2848. }
  2849. }
  2850. CloseHandle( stream->processingThread );
  2851. stream->processingThread = NULL;
  2852. }
  2853. else
  2854. {
  2855. /* blocking read / write stream */
  2856. if( PA_IS_OUTPUT_STREAM_(stream) )
  2857. {
  2858. if( stream->output.framesUsedInCurrentBuffer > 0 )
  2859. {
  2860. /* there are still unqueued frames in the current buffer, so flush them */
  2861. hostOutputBufferIndex = stream->output.currentBufferIndex;
  2862. PaUtil_SetOutputFrameCount( &stream->bufferProcessor,
  2863. stream->output.framesPerBuffer - stream->output.framesUsedInCurrentBuffer );
  2864. channel = 0;
  2865. for( i=0; i<stream->output.deviceCount; ++i )
  2866. {
  2867. /* we have stored the number of channels in the buffer in dwUser */
  2868. int channelCount = (int)stream->output.waveHeaders[i][ hostOutputBufferIndex ].dwUser;
  2869. PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, channel,
  2870. stream->output.waveHeaders[i][ hostOutputBufferIndex ].lpData +
  2871. stream->output.framesUsedInCurrentBuffer * channelCount *
  2872. stream->bufferProcessor.bytesPerHostOutputSample,
  2873. channelCount );
  2874. channel += channelCount;
  2875. }
  2876. PaUtil_ZeroOutput( &stream->bufferProcessor,
  2877. stream->output.framesPerBuffer - stream->output.framesUsedInCurrentBuffer );
  2878. /* we send the entire buffer to the output devices, but we could
  2879. just send a partial buffer, rather than zeroing the unused
  2880. samples.
  2881. */
  2882. AdvanceToNextOutputBuffer( stream );
  2883. }
  2884. timeout = (stream->allBuffersDurationMs / stream->output.bufferCount) + 1;
  2885. if( timeout < PA_MME_MIN_TIMEOUT_MSEC_ )
  2886. timeout = PA_MME_MIN_TIMEOUT_MSEC_;
  2887. waitCount = 0;
  2888. while( !NoBuffersAreQueued( &stream->output ) && waitCount <= stream->output.bufferCount )
  2889. {
  2890. /* wait for MME to signal that a buffer is available */
  2891. waitResult = WaitForSingleObject( stream->output.bufferEvent, timeout );
  2892. if( waitResult == WAIT_FAILED )
  2893. {
  2894. break;
  2895. }
  2896. else if( waitResult == WAIT_TIMEOUT )
  2897. {
  2898. /* keep waiting */
  2899. }
  2900. ++waitCount;
  2901. }
  2902. }
  2903. }
  2904. if( PA_IS_OUTPUT_STREAM_(stream) )
  2905. {
  2906. for( i =0; i < stream->output.deviceCount; ++i )
  2907. {
  2908. mmresult = waveOutReset( ((HWAVEOUT*)stream->output.waveHandles)[i] );
  2909. if( mmresult != MMSYSERR_NOERROR )
  2910. {
  2911. result = paUnanticipatedHostError;
  2912. PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
  2913. }
  2914. }
  2915. }
  2916. if( PA_IS_INPUT_STREAM_(stream) )
  2917. {
  2918. for( i=0; i < stream->input.deviceCount; ++i )
  2919. {
  2920. mmresult = waveInReset( ((HWAVEIN*)stream->input.waveHandles)[i] );
  2921. if( mmresult != MMSYSERR_NOERROR )
  2922. {
  2923. result = paUnanticipatedHostError;
  2924. PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
  2925. }
  2926. }
  2927. }
  2928. stream->isStopped = 1;
  2929. stream->isActive = 0;
  2930. return result;
  2931. }
  2932. static PaError AbortStream( PaStream *s )
  2933. {
  2934. PaError result = paNoError;
  2935. PaWinMmeStream *stream = (PaWinMmeStream*)s;
  2936. int timeout;
  2937. DWORD waitResult;
  2938. MMRESULT mmresult;
  2939. unsigned int i;
  2940. /** @todo
  2941. REVIEW: the error checking in this function needs review. the basic
  2942. idea is to return from this function in a known state - for example
  2943. there is no point avoiding calling waveInReset just because
  2944. the thread times out.
  2945. */
  2946. if( stream->processingThread )
  2947. {
  2948. /* callback stream */
  2949. /* Tell processing thread to abort immediately */
  2950. stream->abortProcessing = 1;
  2951. SetEvent( stream->abortEvent );
  2952. }
  2953. if( PA_IS_OUTPUT_STREAM_(stream) )
  2954. {
  2955. for( i =0; i < stream->output.deviceCount; ++i )
  2956. {
  2957. mmresult = waveOutReset( ((HWAVEOUT*)stream->output.waveHandles)[i] );
  2958. if( mmresult != MMSYSERR_NOERROR )
  2959. {
  2960. PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
  2961. return paUnanticipatedHostError;
  2962. }
  2963. }
  2964. }
  2965. if( PA_IS_INPUT_STREAM_(stream) )
  2966. {
  2967. for( i=0; i < stream->input.deviceCount; ++i )
  2968. {
  2969. mmresult = waveInReset( ((HWAVEIN*)stream->input.waveHandles)[i] );
  2970. if( mmresult != MMSYSERR_NOERROR )
  2971. {
  2972. PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
  2973. return paUnanticipatedHostError;
  2974. }
  2975. }
  2976. }
  2977. if( stream->processingThread )
  2978. {
  2979. /* callback stream */
  2980. PA_DEBUG(("WinMME AbortStream: waiting for background thread.\n"));
  2981. /* Calculate timeOut longer than longest time it could take to return all buffers. */
  2982. timeout = (int)(stream->allBuffersDurationMs * 1.5);
  2983. if( timeout < PA_MME_MIN_TIMEOUT_MSEC_ )
  2984. timeout = PA_MME_MIN_TIMEOUT_MSEC_;
  2985. waitResult = WaitForSingleObject( stream->processingThread, timeout );
  2986. if( waitResult == WAIT_TIMEOUT )
  2987. {
  2988. PA_DEBUG(("WinMME AbortStream: timed out while waiting for background thread to finish.\n"));
  2989. return paTimedOut;
  2990. }
  2991. CloseHandle( stream->processingThread );
  2992. stream->processingThread = NULL;
  2993. }
  2994. stream->isStopped = 1;
  2995. stream->isActive = 0;
  2996. return result;
  2997. }
  2998. static PaError IsStreamStopped( PaStream *s )
  2999. {
  3000. PaWinMmeStream *stream = (PaWinMmeStream*)s;
  3001. return stream->isStopped;
  3002. }
  3003. static PaError IsStreamActive( PaStream *s )
  3004. {
  3005. PaWinMmeStream *stream = (PaWinMmeStream*)s;
  3006. return stream->isActive;
  3007. }
  3008. static PaTime GetStreamTime( PaStream *s )
  3009. {
  3010. (void) s; /* unused parameter */
  3011. return PaUtil_GetTime();
  3012. }
  3013. static double GetStreamCpuLoad( PaStream* s )
  3014. {
  3015. PaWinMmeStream *stream = (PaWinMmeStream*)s;
  3016. return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
  3017. }
  3018. /*
  3019. As separate stream interfaces are used for blocking and callback
  3020. streams, the following functions can be guaranteed to only be called
  3021. for blocking streams.
  3022. */
  3023. static PaError ReadStream( PaStream* s,
  3024. void *buffer,
  3025. unsigned long frames )
  3026. {
  3027. PaError result = paNoError;
  3028. PaWinMmeStream *stream = (PaWinMmeStream*)s;
  3029. void *userBuffer;
  3030. unsigned long framesRead = 0;
  3031. unsigned long framesProcessed;
  3032. signed int hostInputBufferIndex;
  3033. DWORD waitResult;
  3034. DWORD timeout = (unsigned long)(stream->allBuffersDurationMs * 0.5);
  3035. unsigned int channel, i;
  3036. if( PA_IS_INPUT_STREAM_(stream) )
  3037. {
  3038. /* make a local copy of the user buffer pointer(s). this is necessary
  3039. because PaUtil_CopyInput() advances these pointers every time
  3040. it is called.
  3041. */
  3042. if( stream->bufferProcessor.userInputIsInterleaved )
  3043. {
  3044. userBuffer = buffer;
  3045. }
  3046. else
  3047. {
  3048. userBuffer = (void*)alloca( sizeof(void*) * stream->bufferProcessor.inputChannelCount );
  3049. if( !userBuffer )
  3050. return paInsufficientMemory;
  3051. for( i = 0; i<stream->bufferProcessor.inputChannelCount; ++i )
  3052. ((void**)userBuffer)[i] = ((void**)buffer)[i];
  3053. }
  3054. do{
  3055. if( CurrentInputBuffersAreDone( stream ) )
  3056. {
  3057. if( NoBuffersAreQueued( &stream->input ) )
  3058. {
  3059. /** @todo REVIEW: consider what to do if the input overflows.
  3060. do we requeue all of the buffers? should we be running
  3061. a thread to make sure they are always queued?
  3062. see: http://www.portaudio.com/trac/ticket/117
  3063. */
  3064. result = paInputOverflowed;
  3065. }
  3066. hostInputBufferIndex = stream->input.currentBufferIndex;
  3067. PaUtil_SetInputFrameCount( &stream->bufferProcessor,
  3068. stream->input.framesPerBuffer - stream->input.framesUsedInCurrentBuffer );
  3069. channel = 0;
  3070. for( i=0; i<stream->input.deviceCount; ++i )
  3071. {
  3072. /* we have stored the number of channels in the buffer in dwUser */
  3073. int channelCount = (int)stream->input.waveHeaders[i][ hostInputBufferIndex ].dwUser;
  3074. PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, channel,
  3075. stream->input.waveHeaders[i][ hostInputBufferIndex ].lpData +
  3076. stream->input.framesUsedInCurrentBuffer * channelCount *
  3077. stream->bufferProcessor.bytesPerHostInputSample,
  3078. channelCount );
  3079. channel += channelCount;
  3080. }
  3081. framesProcessed = PaUtil_CopyInput( &stream->bufferProcessor, &userBuffer, frames - framesRead );
  3082. stream->input.framesUsedInCurrentBuffer += framesProcessed;
  3083. if( stream->input.framesUsedInCurrentBuffer == stream->input.framesPerBuffer )
  3084. {
  3085. result = AdvanceToNextInputBuffer( stream );
  3086. if( result != paNoError )
  3087. break;
  3088. }
  3089. framesRead += framesProcessed;
  3090. }else{
  3091. /* wait for MME to signal that a buffer is available */
  3092. waitResult = WaitForSingleObject( stream->input.bufferEvent, timeout );
  3093. if( waitResult == WAIT_FAILED )
  3094. {
  3095. result = paUnanticipatedHostError;
  3096. break;
  3097. }
  3098. else if( waitResult == WAIT_TIMEOUT )
  3099. {
  3100. /* if a timeout is encountered, continue,
  3101. perhaps we should give up eventually
  3102. */
  3103. }
  3104. }
  3105. }while( framesRead < frames );
  3106. }
  3107. else
  3108. {
  3109. result = paCanNotReadFromAnOutputOnlyStream;
  3110. }
  3111. return result;
  3112. }
  3113. static PaError WriteStream( PaStream* s,
  3114. const void *buffer,
  3115. unsigned long frames )
  3116. {
  3117. PaError result = paNoError;
  3118. PaWinMmeStream *stream = (PaWinMmeStream*)s;
  3119. const void *userBuffer;
  3120. unsigned long framesWritten = 0;
  3121. unsigned long framesProcessed;
  3122. signed int hostOutputBufferIndex;
  3123. DWORD waitResult;
  3124. DWORD timeout = (unsigned long)(stream->allBuffersDurationMs * 0.5);
  3125. unsigned int channel, i;
  3126. if( PA_IS_OUTPUT_STREAM_(stream) )
  3127. {
  3128. /* make a local copy of the user buffer pointer(s). this is necessary
  3129. because PaUtil_CopyOutput() advances these pointers every time
  3130. it is called.
  3131. */
  3132. if( stream->bufferProcessor.userOutputIsInterleaved )
  3133. {
  3134. userBuffer = buffer;
  3135. }
  3136. else
  3137. {
  3138. userBuffer = (const void*)alloca( sizeof(void*) * stream->bufferProcessor.outputChannelCount );
  3139. if( !userBuffer )
  3140. return paInsufficientMemory;
  3141. for( i = 0; i<stream->bufferProcessor.outputChannelCount; ++i )
  3142. ((const void**)userBuffer)[i] = ((const void**)buffer)[i];
  3143. }
  3144. do{
  3145. if( CurrentOutputBuffersAreDone( stream ) )
  3146. {
  3147. if( NoBuffersAreQueued( &stream->output ) )
  3148. {
  3149. /** @todo REVIEW: consider what to do if the output
  3150. underflows. do we requeue all the existing buffers with
  3151. zeros? should we run a separate thread to keep the buffers
  3152. enqueued at all times?
  3153. see: http://www.portaudio.com/trac/ticket/117
  3154. */
  3155. result = paOutputUnderflowed;
  3156. }
  3157. hostOutputBufferIndex = stream->output.currentBufferIndex;
  3158. PaUtil_SetOutputFrameCount( &stream->bufferProcessor,
  3159. stream->output.framesPerBuffer - stream->output.framesUsedInCurrentBuffer );
  3160. channel = 0;
  3161. for( i=0; i<stream->output.deviceCount; ++i )
  3162. {
  3163. /* we have stored the number of channels in the buffer in dwUser */
  3164. int channelCount = (int)stream->output.waveHeaders[i][ hostOutputBufferIndex ].dwUser;
  3165. PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, channel,
  3166. stream->output.waveHeaders[i][ hostOutputBufferIndex ].lpData +
  3167. stream->output.framesUsedInCurrentBuffer * channelCount *
  3168. stream->bufferProcessor.bytesPerHostOutputSample,
  3169. channelCount );
  3170. channel += channelCount;
  3171. }
  3172. framesProcessed = PaUtil_CopyOutput( &stream->bufferProcessor, &userBuffer, frames - framesWritten );
  3173. stream->output.framesUsedInCurrentBuffer += framesProcessed;
  3174. if( stream->output.framesUsedInCurrentBuffer == stream->output.framesPerBuffer )
  3175. {
  3176. result = AdvanceToNextOutputBuffer( stream );
  3177. if( result != paNoError )
  3178. break;
  3179. }
  3180. framesWritten += framesProcessed;
  3181. }
  3182. else
  3183. {
  3184. /* wait for MME to signal that a buffer is available */
  3185. waitResult = WaitForSingleObject( stream->output.bufferEvent, timeout );
  3186. if( waitResult == WAIT_FAILED )
  3187. {
  3188. result = paUnanticipatedHostError;
  3189. break;
  3190. }
  3191. else if( waitResult == WAIT_TIMEOUT )
  3192. {
  3193. /* if a timeout is encountered, continue,
  3194. perhaps we should give up eventually
  3195. */
  3196. }
  3197. }
  3198. }while( framesWritten < frames );
  3199. }
  3200. else
  3201. {
  3202. result = paCanNotWriteToAnInputOnlyStream;
  3203. }
  3204. return result;
  3205. }
  3206. static signed long GetStreamReadAvailable( PaStream* s )
  3207. {
  3208. PaWinMmeStream *stream = (PaWinMmeStream*)s;
  3209. if( PA_IS_INPUT_STREAM_(stream) )
  3210. return GetAvailableFrames( &stream->input );
  3211. else
  3212. return paCanNotReadFromAnOutputOnlyStream;
  3213. }
  3214. static signed long GetStreamWriteAvailable( PaStream* s )
  3215. {
  3216. PaWinMmeStream *stream = (PaWinMmeStream*)s;
  3217. if( PA_IS_OUTPUT_STREAM_(stream) )
  3218. return GetAvailableFrames( &stream->output );
  3219. else
  3220. return paCanNotWriteToAnInputOnlyStream;
  3221. }
  3222. /* NOTE: the following functions are MME-stream specific, and are called directly
  3223. by client code. We need to check for many more error conditions here because
  3224. we don't have the benefit of pa_front.c's parameter checking.
  3225. */
  3226. static PaError GetWinMMEStreamPointer( PaWinMmeStream **stream, PaStream *s )
  3227. {
  3228. PaError result;
  3229. PaUtilHostApiRepresentation *hostApi;
  3230. PaWinMmeHostApiRepresentation *winMmeHostApi;
  3231. result = PaUtil_ValidateStreamPointer( s );
  3232. if( result != paNoError )
  3233. return result;
  3234. result = PaUtil_GetHostApiRepresentation( &hostApi, paMME );
  3235. if( result != paNoError )
  3236. return result;
  3237. winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi;
  3238. /* note, the following would be easier if there was a generic way of testing
  3239. that a stream belongs to a specific host API */
  3240. if( PA_STREAM_REP( s )->streamInterface == &winMmeHostApi->callbackStreamInterface
  3241. || PA_STREAM_REP( s )->streamInterface == &winMmeHostApi->blockingStreamInterface )
  3242. {
  3243. /* s is a WinMME stream */
  3244. *stream = (PaWinMmeStream *)s;
  3245. return paNoError;
  3246. }
  3247. else
  3248. {
  3249. return paIncompatibleStreamHostApi;
  3250. }
  3251. }
  3252. int PaWinMME_GetStreamInputHandleCount( PaStream* s )
  3253. {
  3254. PaWinMmeStream *stream;
  3255. PaError result = GetWinMMEStreamPointer( &stream, s );
  3256. if( result == paNoError )
  3257. return (PA_IS_INPUT_STREAM_(stream)) ? stream->input.deviceCount : 0;
  3258. else
  3259. return result;
  3260. }
  3261. HWAVEIN PaWinMME_GetStreamInputHandle( PaStream* s, int handleIndex )
  3262. {
  3263. PaWinMmeStream *stream;
  3264. PaError result = GetWinMMEStreamPointer( &stream, s );
  3265. if( result == paNoError
  3266. && PA_IS_INPUT_STREAM_(stream)
  3267. && handleIndex >= 0
  3268. && (unsigned int)handleIndex < stream->input.deviceCount )
  3269. return ((HWAVEIN*)stream->input.waveHandles)[handleIndex];
  3270. else
  3271. return 0;
  3272. }
  3273. int PaWinMME_GetStreamOutputHandleCount( PaStream* s)
  3274. {
  3275. PaWinMmeStream *stream;
  3276. PaError result = GetWinMMEStreamPointer( &stream, s );
  3277. if( result == paNoError )
  3278. return (PA_IS_OUTPUT_STREAM_(stream)) ? stream->output.deviceCount : 0;
  3279. else
  3280. return result;
  3281. }
  3282. HWAVEOUT PaWinMME_GetStreamOutputHandle( PaStream* s, int handleIndex )
  3283. {
  3284. PaWinMmeStream *stream;
  3285. PaError result = GetWinMMEStreamPointer( &stream, s );
  3286. if( result == paNoError
  3287. && PA_IS_OUTPUT_STREAM_(stream)
  3288. && handleIndex >= 0
  3289. && (unsigned int)handleIndex < stream->output.deviceCount )
  3290. return ((HWAVEOUT*)stream->output.waveHandles)[handleIndex];
  3291. else
  3292. return 0;
  3293. }
  3294. #endif