12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656 |
- /*
- * $Id: pa_win_wdmks.c 1885 2012-12-28 16:54:25Z robiwan $
- * PortAudio Windows WDM-KS interface
- *
- * Author: Andrew Baldwin, Robert Bielik (WaveRT)
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2004 Andrew Baldwin, Ross Bencina, Phil Burk
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
- /*
- * The text above constitutes the entire PortAudio license; however,
- * the PortAudio community also makes the following non-binding requests:
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version. It is also
- * requested that these non-binding requests be included along with the
- * license above.
- */
- /** @file
- @ingroup hostapi_src
- @brief Portaudio WDM-KS host API.
- @note This is the implementation of the Portaudio host API using the
- Windows WDM/Kernel Streaming API in order to enable very low latency
- playback and recording on all modern Windows platforms (e.g. 2K, XP, Vista, Win7)
- Note: This API accesses the device drivers below the usual KMIXER
- component which is normally used to enable multi-client mixing and
- format conversion. That means that it will lock out all other users
- of a device for the duration of active stream using those devices
- */
- #include <stdio.h>
- #if (defined(_WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) /* MSC version 6 and above */
- #pragma comment( lib, "setupapi.lib" )
- #endif
- /* Debugging/tracing support */
- #define PA_LOGE_
- #define PA_LOGL_
- #ifdef __GNUC__
- #include <initguid.h>
- #define _WIN32_WINNT 0x0501
- #define WINVER 0x0501
- #endif
- #include <string.h> /* strlen() */
- #include <assert.h>
- #include <wchar.h> /* iswspace() */
- #include "pa_util.h"
- #include "pa_allocation.h"
- #include "pa_hostapi.h"
- #include "pa_stream.h"
- #include "pa_cpuload.h"
- #include "pa_process.h"
- #include "portaudio.h"
- #include "pa_debugprint.h"
- #include "pa_memorybarrier.h"
- #include "pa_ringbuffer.h"
- #include "pa_trace.h"
- #include "pa_win_waveformat.h"
- #include "pa_win_wdmks.h"
- #include <windows.h>
- #include <winioctl.h>
- #include <process.h>
- #include <math.h>
- #ifdef _MSC_VER
- #define snprintf _snprintf
- #define vsnprintf _vsnprintf
- #endif
- /* The PA_HP_TRACE macro is used in RT parts, so it can be switched off without affecting
- the rest of the debug tracing */
- #if 1
- #define PA_HP_TRACE(x) PaUtil_AddHighSpeedLogMessage x ;
- #else
- #define PA_HP_TRACE(x)
- #endif
- /* A define that selects whether the resulting pin names are chosen from pin category
- instead of the available pin names, who sometimes can be quite cheesy, like "Volume control".
- Default is to use the pin category.
- */
- #ifndef PA_WDMKS_USE_CATEGORY_FOR_PIN_NAMES
- #define PA_WDMKS_USE_CATEGORY_FOR_PIN_NAMES 1
- #endif
- #ifdef __GNUC__
- #undef PA_LOGE_
- #define PA_LOGE_ PA_DEBUG(("%s {\n",__FUNCTION__))
- #undef PA_LOGL_
- #define PA_LOGL_ PA_DEBUG(("} %s\n",__FUNCTION__))
- /* These defines are set in order to allow the WIndows DirectX
- * headers to compile with a GCC compiler such as MinGW
- * NOTE: The headers may generate a few warning in GCC, but
- * they should compile */
- #define _INC_MMSYSTEM
- #define _INC_MMREG
- #define _NTRTL_ /* Turn off default definition of DEFINE_GUIDEX */
- #define DEFINE_GUID_THUNK(name,guid) DEFINE_GUID(name,guid)
- #define DEFINE_GUIDEX(n) DEFINE_GUID_THUNK( n, STATIC_##n )
- #if !defined( DEFINE_WAVEFORMATEX_GUID )
- #define DEFINE_WAVEFORMATEX_GUID(x) (USHORT)(x), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
- #endif
- #define WAVE_FORMAT_ADPCM 0x0002
- #define WAVE_FORMAT_IEEE_FLOAT 0x0003
- #define WAVE_FORMAT_ALAW 0x0006
- #define WAVE_FORMAT_MULAW 0x0007
- #define WAVE_FORMAT_MPEG 0x0050
- #define WAVE_FORMAT_DRM 0x0009
- #define DYNAMIC_GUID_THUNK(l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
- #define DYNAMIC_GUID(data) DYNAMIC_GUID_THUNK(data)
- #endif
- /* use CreateThread for CYGWIN/Windows Mobile, _beginthreadex for all others */
- #if !defined(__CYGWIN__) && !defined(_WIN32_WCE)
- #define CREATE_THREAD_FUNCTION (HANDLE)_beginthreadex
- #define PA_THREAD_FUNC static unsigned WINAPI
- #else
- #define CREATE_THREAD_FUNCTION CreateThread
- #define PA_THREAD_FUNC static DWORD WINAPI
- #endif
- #ifdef _MSC_VER
- #define NOMMIDS
- #define DYNAMIC_GUID(data) {data}
- #define _NTRTL_ /* Turn off default definition of DEFINE_GUIDEX */
- #undef DEFINE_GUID
- #define DEFINE_GUID(n,data) EXTERN_C const GUID n = {data}
- #define DEFINE_GUID_THUNK(n,data) DEFINE_GUID(n,data)
- #define DEFINE_GUIDEX(n) DEFINE_GUID_THUNK(n, STATIC_##n)
- #endif
- #include <setupapi.h>
- #ifndef EXTERN_C
- #define EXTERN_C extern
- #endif
- #if defined(__GNUC__)
- /* For MinGW we reference mingw-include files supplied with WASAPI */
- #define WINBOOL BOOL
- #include "../wasapi/mingw-include/ks.h"
- #include "../wasapi/mingw-include/ksmedia.h"
- #else
- #include <mmreg.h>
- #include <ks.h>
- /* Note that Windows SDK V6.0A or later is needed for WaveRT specific structs to be present in
- ksmedia.h. Also make sure that the SDK include path is before other include paths (that may contain
- an "old" ksmedia.h), so the proper ksmedia.h is used */
- #include <ksmedia.h>
- #endif
- #include <assert.h>
- #include <stdio.h>
- /* These next definitions allow the use of the KSUSER DLL */
- typedef /*KSDDKAPI*/ DWORD WINAPI KSCREATEPIN(HANDLE, PKSPIN_CONNECT, ACCESS_MASK, PHANDLE);
- extern HMODULE DllKsUser;
- extern KSCREATEPIN* FunctionKsCreatePin;
- /* These definitions allows the use of AVRT.DLL on Vista and later OSs */
- typedef enum _PA_AVRT_PRIORITY
- {
- PA_AVRT_PRIORITY_LOW = -1,
- PA_AVRT_PRIORITY_NORMAL,
- PA_AVRT_PRIORITY_HIGH,
- PA_AVRT_PRIORITY_CRITICAL
- } PA_AVRT_PRIORITY, *PPA_AVRT_PRIORITY;
- typedef struct
- {
- HINSTANCE hInstance;
- HANDLE (WINAPI *AvSetMmThreadCharacteristics) (LPCSTR, LPDWORD);
- BOOL (WINAPI *AvRevertMmThreadCharacteristics) (HANDLE);
- BOOL (WINAPI *AvSetMmThreadPriority) (HANDLE, PA_AVRT_PRIORITY);
- } PaWinWDMKSAvRtEntryPoints;
- static PaWinWDMKSAvRtEntryPoints paWinWDMKSAvRtEntryPoints = {0};
- /* An unspecified channel count (-1) is not treated correctly, so we replace it with
- * an arbitrarily large number */
- #define MAXIMUM_NUMBER_OF_CHANNELS 256
- /* Forward definition to break circular type reference between pin and filter */
- struct __PaWinWdmFilter;
- typedef struct __PaWinWdmFilter PaWinWdmFilter;
- struct __PaWinWdmPin;
- typedef struct __PaWinWdmPin PaWinWdmPin;
- struct __PaWinWdmStream;
- typedef struct __PaWinWdmStream PaWinWdmStream;
- /* Function prototype for getting audio position */
- typedef PaError (*FunctionGetPinAudioPosition)(PaWinWdmPin*, unsigned long*);
- /* Function prototype for memory barrier */
- typedef void (*FunctionMemoryBarrier)(void);
- struct __PaProcessThreadInfo;
- typedef struct __PaProcessThreadInfo PaProcessThreadInfo;
- typedef PaError (*FunctionPinHandler)(PaProcessThreadInfo* pInfo, unsigned eventIndex);
- typedef enum __PaStreamStartEnum
- {
- StreamStart_kOk,
- StreamStart_kFailed,
- StreamStart_kCnt
- } PaStreamStartEnum;
- /* Multiplexed input structure.
- * Very often several physical inputs are multiplexed through a MUX node (represented in the topology filter) */
- typedef struct __PaWinWdmMuxedInput
- {
- wchar_t friendlyName[MAX_PATH];
- ULONG muxPinId;
- ULONG muxNodeId;
- ULONG endpointPinId;
- } PaWinWdmMuxedInput;
- /* The Pin structure
- * A pin is an input or output node, e.g. for audio flow */
- struct __PaWinWdmPin
- {
- HANDLE handle;
- PaWinWdmMuxedInput** inputs;
- unsigned inputCount;
- wchar_t friendlyName[MAX_PATH];
- PaWinWdmFilter* parentFilter;
- PaWDMKSSubType pinKsSubType;
- unsigned long pinId;
- unsigned long endpointPinId; /* For output pins */
- KSPIN_CONNECT* pinConnect;
- unsigned long pinConnectSize;
- KSDATAFORMAT_WAVEFORMATEX* ksDataFormatWfx;
- KSPIN_COMMUNICATION communication;
- KSDATARANGE* dataRanges;
- KSMULTIPLE_ITEM* dataRangesItem;
- KSPIN_DATAFLOW dataFlow;
- KSPIN_CINSTANCES instances;
- unsigned long frameSize;
- int maxChannels;
- unsigned long formats;
- int defaultSampleRate;
- ULONG *positionRegister; /* WaveRT */
- ULONG hwLatency; /* WaveRT */
- FunctionMemoryBarrier fnMemBarrier; /* WaveRT */
- FunctionGetPinAudioPosition fnAudioPosition; /* WaveRT */
- FunctionPinHandler fnEventHandler;
- FunctionPinHandler fnSubmitHandler;
- };
- /* The Filter structure
- * A filter has a number of pins and a "friendly name" */
- struct __PaWinWdmFilter
- {
- HANDLE handle;
- PaWinWDMKSDeviceInfo devInfo; /* This will hold information that is exposed in PaDeviceInfo */
- DWORD deviceNode;
- int pinCount;
- PaWinWdmPin** pins;
- PaWinWdmFilter* topologyFilter;
- wchar_t friendlyName[MAX_PATH];
- int validPinCount;
- int usageCount;
- KSMULTIPLE_ITEM* connections;
- KSMULTIPLE_ITEM* nodes;
- int filterRefCount;
- };
- typedef struct __PaWinWdmDeviceInfo
- {
- PaDeviceInfo inheritedDeviceInfo;
- char compositeName[MAX_PATH]; /* Composite name consists of pin name + device name in utf8 */
- PaWinWdmFilter* filter;
- unsigned long pin;
- int muxPosition; /* Used only for input devices */
- int endpointPinId;
- }
- PaWinWdmDeviceInfo;
- /* PaWinWdmHostApiRepresentation - host api datastructure specific to this implementation */
- typedef struct __PaWinWdmHostApiRepresentation
- {
- PaUtilHostApiRepresentation inheritedHostApiRep;
- PaUtilStreamInterface callbackStreamInterface;
- PaUtilStreamInterface blockingStreamInterface;
- PaUtilAllocationGroup* allocations;
- int deviceCount;
- }
- PaWinWdmHostApiRepresentation;
- typedef struct __DATAPACKET
- {
- KSSTREAM_HEADER Header;
- OVERLAPPED Signal;
- } DATAPACKET;
- typedef struct __PaIOPacket
- {
- DATAPACKET* packet;
- unsigned startByte;
- unsigned lengthBytes;
- } PaIOPacket;
- typedef struct __PaWinWdmIOInfo
- {
- PaWinWdmPin* pPin;
- char* hostBuffer;
- unsigned hostBufferSize;
- unsigned framesPerBuffer;
- unsigned bytesPerFrame;
- unsigned bytesPerSample;
- unsigned noOfPackets; /* Only used in WaveCyclic */
- HANDLE *events; /* noOfPackets handles (WaveCyclic) 1 (WaveRT) */
- DATAPACKET *packets; /* noOfPackets packets (WaveCyclic) 2 (WaveRT) */
- /* WaveRT polled mode */
- unsigned lastPosition;
- unsigned pollCntr;
- } PaWinWdmIOInfo;
- /* PaWinWdmStream - a stream data structure specifically for this implementation */
- struct __PaWinWdmStream
- {
- PaUtilStreamRepresentation streamRepresentation;
- PaWDMKSSpecificStreamInfo hostApiStreamInfo; /* This holds info that is exposed through PaStreamInfo */
- PaUtilCpuLoadMeasurer cpuLoadMeasurer;
- PaUtilBufferProcessor bufferProcessor;
- #if PA_TRACE_REALTIME_EVENTS
- LogHandle hLog;
- #endif
- PaUtilAllocationGroup* allocGroup;
- PaWinWdmIOInfo capture;
- PaWinWdmIOInfo render;
- int streamStarted;
- int streamActive;
- int streamStop;
- int streamAbort;
- int oldProcessPriority;
- HANDLE streamThread;
- HANDLE eventAbort;
- HANDLE eventStreamStart[StreamStart_kCnt]; /* 0 = OK, 1 = Failed */
- PaError threadResult;
- PaStreamFlags streamFlags;
- /* Capture ring buffer */
- PaUtilRingBuffer ringBuffer;
- char* ringBufferData;
- /* These values handle the case where the user wants to use fewer
- * channels than the device has */
- int userInputChannels;
- int deviceInputChannels;
- int userOutputChannels;
- int deviceOutputChannels;
- };
- /* Gather all processing variables in a struct */
- struct __PaProcessThreadInfo
- {
- PaWinWdmStream *stream;
- PaStreamCallbackTimeInfo ti;
- PaStreamCallbackFlags underover;
- int cbResult;
- volatile int pending;
- volatile int priming;
- volatile int pinsStarted;
- unsigned long timeout;
- unsigned captureHead;
- unsigned captureTail;
- unsigned renderHead;
- unsigned renderTail;
- PaIOPacket capturePackets[4];
- PaIOPacket renderPackets[4];
- };
- /* Used for transferring device infos during scanning / rescanning */
- typedef struct __PaWinWDMScanDeviceInfosResults
- {
- PaDeviceInfo **deviceInfos;
- PaDeviceIndex defaultInputDevice;
- PaDeviceIndex defaultOutputDevice;
- } PaWinWDMScanDeviceInfosResults;
- static const unsigned cPacketsArrayMask = 3;
- HMODULE DllKsUser = NULL;
- KSCREATEPIN* FunctionKsCreatePin = NULL;
- /* prototypes for functions declared in this file */
- #ifdef __cplusplus
- extern "C"
- {
- #endif /* __cplusplus */
- PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
- #ifdef __cplusplus
- }
- #endif /* __cplusplus */
- /* Low level I/O functions */
- static PaError WdmSyncIoctl(HANDLE handle,
- unsigned long ioctlNumber,
- void* inBuffer,
- unsigned long inBufferCount,
- void* outBuffer,
- unsigned long outBufferCount,
- unsigned long* bytesReturned);
- static PaError WdmGetPropertySimple(HANDLE handle,
- const GUID* const guidPropertySet,
- unsigned long property,
- void* value,
- unsigned long valueCount);
- static PaError WdmSetPropertySimple(HANDLE handle,
- const GUID* const guidPropertySet,
- unsigned long property,
- void* value,
- unsigned long valueCount,
- void* instance,
- unsigned long instanceCount);
- static PaError WdmGetPinPropertySimple(HANDLE handle,
- unsigned long pinId,
- const GUID* const guidPropertySet,
- unsigned long property,
- void* value,
- unsigned long valueCount,
- unsigned long* byteCount);
- static PaError WdmGetPinPropertyMulti(HANDLE handle,
- unsigned long pinId,
- const GUID* const guidPropertySet,
- unsigned long property,
- KSMULTIPLE_ITEM** ksMultipleItem);
- static PaError WdmGetPropertyMulti(HANDLE handle,
- const GUID* const guidPropertySet,
- unsigned long property,
- KSMULTIPLE_ITEM** ksMultipleItem);
- static PaError WdmSetMuxNodeProperty(HANDLE handle,
- ULONG nodeId,
- ULONG pinId);
- /** Pin management functions */
- static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, PaError* error);
- static void PinFree(PaWinWdmPin* pin);
- static void PinClose(PaWinWdmPin* pin);
- static PaError PinInstantiate(PaWinWdmPin* pin);
- /*static PaError PinGetState(PaWinWdmPin* pin, KSSTATE* state); NOT USED */
- static PaError PinSetState(PaWinWdmPin* pin, KSSTATE state);
- static PaError PinSetFormat(PaWinWdmPin* pin, const WAVEFORMATEX* format);
- static PaError PinIsFormatSupported(PaWinWdmPin* pin, const WAVEFORMATEX* format);
- /* WaveRT support */
- static PaError PinQueryNotificationSupport(PaWinWdmPin* pPin, BOOL* pbResult);
- static PaError PinGetBuffer(PaWinWdmPin* pPin, void** pBuffer, DWORD* pRequestedBufSize, BOOL* pbCallMemBarrier);
- static PaError PinRegisterPositionRegister(PaWinWdmPin* pPin);
- static PaError PinRegisterNotificationHandle(PaWinWdmPin* pPin, HANDLE handle);
- static PaError PinUnregisterNotificationHandle(PaWinWdmPin* pPin, HANDLE handle);
- static PaError PinGetHwLatency(PaWinWdmPin* pPin, ULONG* pFifoSize, ULONG* pChipsetDelay, ULONG* pCodecDelay);
- static PaError PinGetAudioPositionDirect(PaWinWdmPin* pPin, ULONG* pPosition);
- static PaError PinGetAudioPositionViaIOCTL(PaWinWdmPin* pPin, ULONG* pPosition);
- /* Filter management functions */
- static PaWinWdmFilter* FilterNew(PaWDMKSType type, DWORD devNode, const wchar_t* filterName, const wchar_t* friendlyName, PaError* error);
- static PaError FilterInitializePins(PaWinWdmFilter* filter);
- static void FilterFree(PaWinWdmFilter* filter);
- static void FilterAddRef(PaWinWdmFilter* filter);
- static PaWinWdmPin* FilterCreatePin(
- PaWinWdmFilter* filter,
- int pinId,
- const WAVEFORMATEX* wfex,
- PaError* error);
- static PaError FilterUse(PaWinWdmFilter* filter);
- static void FilterRelease(PaWinWdmFilter* filter);
- /* Hot plug functions */
- static BOOL IsDeviceTheSame(const PaWinWdmDeviceInfo* pDev1,
- const PaWinWdmDeviceInfo* pDev2);
- /* Interface functions */
- static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
- static PaError IsFormatSupported(
- struct PaUtilHostApiRepresentation *hostApi,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate );
- static PaError ScanDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, void **newDeviceInfos, int *newDeviceCount );
- static PaError CommitDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, void *deviceInfos, int deviceCount );
- static PaError DisposeDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, void *deviceInfos, int deviceCount );
- static PaError OpenStream(
- struct PaUtilHostApiRepresentation *hostApi,
- PaStream** s,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate,
- unsigned long framesPerBuffer,
- PaStreamFlags streamFlags,
- PaStreamCallback *streamCallback,
- void *userData );
- static PaError CloseStream( PaStream* stream );
- static PaError StartStream( PaStream *stream );
- static PaError StopStream( PaStream *stream );
- static PaError AbortStream( PaStream *stream );
- static PaError IsStreamStopped( PaStream *s );
- static PaError IsStreamActive( PaStream *stream );
- static PaTime GetStreamTime( PaStream *stream );
- static double GetStreamCpuLoad( PaStream* stream );
- static PaError ReadStream(
- PaStream* stream,
- void *buffer,
- unsigned long frames );
- static PaError WriteStream(
- PaStream* stream,
- const void *buffer,
- unsigned long frames );
- static signed long GetStreamReadAvailable( PaStream* stream );
- static signed long GetStreamWriteAvailable( PaStream* stream );
- /* Utility functions */
- static unsigned long GetWfexSize(const WAVEFORMATEX* wfex);
- static PaWinWdmFilter** BuildFilterList(int* filterCount, int* noOfPaDevices, PaError* result);
- static BOOL PinWrite(HANDLE h, DATAPACKET* p);
- static BOOL PinRead(HANDLE h, DATAPACKET* p);
- static void DuplicateFirstChannelInt16(void* buffer, int channels, int samples);
- static void DuplicateFirstChannelInt24(void* buffer, int channels, int samples);
- PA_THREAD_FUNC ProcessingThread(void*);
- /* Pin handler functions */
- static PaError PaPinCaptureEventHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex);
- static PaError PaPinCaptureSubmitHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex);
- static PaError PaPinRenderEventHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex);
- static PaError PaPinRenderSubmitHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex);
- static PaError PaPinCaptureEventHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex);
- static PaError PaPinCaptureEventHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex);
- static PaError PaPinCaptureSubmitHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex);
- static PaError PaPinCaptureSubmitHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex);
- static PaError PaPinRenderEventHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex);
- static PaError PaPinRenderEventHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex);
- static PaError PaPinRenderSubmitHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex);
- static PaError PaPinRenderSubmitHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex);
- /* Function bodies */
- #if defined(_DEBUG) && defined(PA_ENABLE_DEBUG_OUTPUT)
- #define PA_WDMKS_SET_TREF
- static PaTime tRef = 0;
- static void PaWinWdmDebugPrintf(const char* fmt, ...)
- {
- va_list list;
- char buffer[1024];
- PaTime t = PaUtil_GetTime() - tRef;
- va_start(list, fmt);
- _vsnprintf(buffer, 1023, fmt, list);
- va_end(list);
- PaUtil_DebugPrint("%6.3lf: %s", t, buffer);
- }
- #ifdef PA_DEBUG
- #undef PA_DEBUG
- #define PA_DEBUG(x) PaWinWdmDebugPrintf x ;
- #endif
- #endif
- static BOOL IsDeviceTheSame(const PaWinWdmDeviceInfo* pDev1,
- const PaWinWdmDeviceInfo* pDev2)
- {
- if (pDev1 == NULL || pDev2 == NULL)
- return FALSE;
- if (pDev1 == pDev2)
- return TRUE;
- if (strcmp(pDev1->compositeName, pDev2->compositeName) == 0)
- return TRUE;
- return FALSE;
- }
- static BOOL IsEarlierThanVista()
- {
- OSVERSIONINFO osvi;
- osvi.dwOSVersionInfoSize = sizeof(osvi);
- if (GetVersionEx(&osvi) && osvi.dwMajorVersion<6)
- {
- return TRUE;
- }
- return FALSE;
- }
- static void MemoryBarrierDummy(void)
- {
- /* Do nothing */
- }
- static void MemoryBarrierRead(void)
- {
- PaUtil_ReadMemoryBarrier();
- }
- static void MemoryBarrierWrite(void)
- {
- PaUtil_WriteMemoryBarrier();
- }
- static unsigned long GetWfexSize(const WAVEFORMATEX* wfex)
- {
- if( wfex->wFormatTag == WAVE_FORMAT_PCM )
- {
- return sizeof( WAVEFORMATEX );
- }
- else
- {
- return (sizeof( WAVEFORMATEX ) + wfex->cbSize);
- }
- }
- static void PaWinWDM_SetLastErrorInfo(long errCode, const char* fmt, ...)
- {
- va_list list;
- char buffer[1024];
- va_start(list, fmt);
- _vsnprintf(buffer, 1023, fmt, list);
- va_end(list);
- PaUtil_SetLastHostErrorInfo(paWDMKS, errCode, buffer);
- }
- /*
- Low level pin/filter access functions
- */
- static PaError WdmSyncIoctl(
- HANDLE handle,
- unsigned long ioctlNumber,
- void* inBuffer,
- unsigned long inBufferCount,
- void* outBuffer,
- unsigned long outBufferCount,
- unsigned long* bytesReturned)
- {
- PaError result = paNoError;
- unsigned long dummyBytesReturned = 0;
- BOOL bRes;
- if( !bytesReturned )
- {
- /* Use a dummy as the caller hasn't supplied one */
- bytesReturned = &dummyBytesReturned;
- }
- bRes = DeviceIoControl(handle, ioctlNumber, inBuffer, inBufferCount, outBuffer, outBufferCount, bytesReturned, NULL);
- if (!bRes)
- {
- unsigned long error = GetLastError();
- if ( !(((error == ERROR_INSUFFICIENT_BUFFER ) || ( error == ERROR_MORE_DATA )) &&
- ( ioctlNumber == IOCTL_KS_PROPERTY ) &&
- ( outBufferCount == 0 ) ) )
- {
- KSPROPERTY* ksProperty = (KSPROPERTY*)inBuffer;
- PaWinWDM_SetLastErrorInfo(result, "WdmSyncIoctl: DeviceIoControl GLE = 0x%08X (prop_set = {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}, prop_id = %u)",
- error,
- ksProperty->Set.Data1, ksProperty->Set.Data2, ksProperty->Set.Data3,
- ksProperty->Set.Data4[0], ksProperty->Set.Data4[1],
- ksProperty->Set.Data4[2], ksProperty->Set.Data4[3],
- ksProperty->Set.Data4[4], ksProperty->Set.Data4[5],
- ksProperty->Set.Data4[6], ksProperty->Set.Data4[7],
- ksProperty->Id
- );
- result = paUnanticipatedHostError;
- }
- }
- return result;
- }
- static PaError WdmGetPropertySimple(HANDLE handle,
- const GUID* const guidPropertySet,
- unsigned long property,
- void* value,
- unsigned long valueCount)
- {
- PaError result;
- KSPROPERTY ksProperty;
- ksProperty.Set = *guidPropertySet;
- ksProperty.Id = property;
- ksProperty.Flags = KSPROPERTY_TYPE_GET;
- result = WdmSyncIoctl(
- handle,
- IOCTL_KS_PROPERTY,
- &ksProperty,
- sizeof(KSPROPERTY),
- value,
- valueCount,
- NULL);
- return result;
- }
- static PaError WdmSetPropertySimple(
- HANDLE handle,
- const GUID* const guidPropertySet,
- unsigned long property,
- void* value,
- unsigned long valueCount,
- void* instance,
- unsigned long instanceCount)
- {
- PaError result;
- KSPROPERTY* ksProperty;
- unsigned long propertyCount = 0;
- propertyCount = sizeof(KSPROPERTY) + instanceCount;
- ksProperty = (KSPROPERTY*)_alloca( propertyCount );
- if( !ksProperty )
- {
- return paInsufficientMemory;
- }
- ksProperty->Set = *guidPropertySet;
- ksProperty->Id = property;
- ksProperty->Flags = KSPROPERTY_TYPE_SET;
- if( instance )
- {
- memcpy((void*)((char*)ksProperty + sizeof(KSPROPERTY)), instance, instanceCount);
- }
- result = WdmSyncIoctl(
- handle,
- IOCTL_KS_PROPERTY,
- ksProperty,
- propertyCount,
- value,
- valueCount,
- NULL);
- return result;
- }
- static PaError WdmGetPinPropertySimple(
- HANDLE handle,
- unsigned long pinId,
- const GUID* const guidPropertySet,
- unsigned long property,
- void* value,
- unsigned long valueCount,
- unsigned long *byteCount)
- {
- PaError result;
- KSP_PIN ksPProp;
- ksPProp.Property.Set = *guidPropertySet;
- ksPProp.Property.Id = property;
- ksPProp.Property.Flags = KSPROPERTY_TYPE_GET;
- ksPProp.PinId = pinId;
- ksPProp.Reserved = 0;
- result = WdmSyncIoctl(
- handle,
- IOCTL_KS_PROPERTY,
- &ksPProp,
- sizeof(KSP_PIN),
- value,
- valueCount,
- byteCount);
- return result;
- }
- static PaError WdmGetPinPropertyMulti(
- HANDLE handle,
- unsigned long pinId,
- const GUID* const guidPropertySet,
- unsigned long property,
- KSMULTIPLE_ITEM** ksMultipleItem)
- {
- PaError result;
- unsigned long multipleItemSize = 0;
- KSP_PIN ksPProp;
- ksPProp.Property.Set = *guidPropertySet;
- ksPProp.Property.Id = property;
- ksPProp.Property.Flags = KSPROPERTY_TYPE_GET;
- ksPProp.PinId = pinId;
- ksPProp.Reserved = 0;
- result = WdmSyncIoctl(
- handle,
- IOCTL_KS_PROPERTY,
- &ksPProp.Property,
- sizeof(KSP_PIN),
- NULL,
- 0,
- &multipleItemSize);
- if( result != paNoError )
- {
- return result;
- }
- *ksMultipleItem = (KSMULTIPLE_ITEM*)PaUtil_AllocateMemory( multipleItemSize );
- if( !*ksMultipleItem )
- {
- return paInsufficientMemory;
- }
- result = WdmSyncIoctl(
- handle,
- IOCTL_KS_PROPERTY,
- &ksPProp,
- sizeof(KSP_PIN),
- (void*)*ksMultipleItem,
- multipleItemSize,
- NULL);
- if( result != paNoError )
- {
- PaUtil_FreeMemory( ksMultipleItem );
- }
- return result;
- }
- static PaError WdmGetPropertyMulti(HANDLE handle,
- const GUID* const guidPropertySet,
- unsigned long property,
- KSMULTIPLE_ITEM** ksMultipleItem)
- {
- PaError result;
- unsigned long multipleItemSize = 0;
- KSPROPERTY ksProp;
- ksProp.Set = *guidPropertySet;
- ksProp.Id = property;
- ksProp.Flags = KSPROPERTY_TYPE_GET;
- result = WdmSyncIoctl(
- handle,
- IOCTL_KS_PROPERTY,
- &ksProp,
- sizeof(KSPROPERTY),
- NULL,
- 0,
- &multipleItemSize);
- if( result != paNoError )
- {
- return result;
- }
- *ksMultipleItem = (KSMULTIPLE_ITEM*)PaUtil_AllocateMemory( multipleItemSize );
- if( !*ksMultipleItem )
- {
- return paInsufficientMemory;
- }
- result = WdmSyncIoctl(
- handle,
- IOCTL_KS_PROPERTY,
- &ksProp,
- sizeof(KSPROPERTY),
- (void*)*ksMultipleItem,
- multipleItemSize,
- NULL);
- if( result != paNoError )
- {
- PaUtil_FreeMemory( ksMultipleItem );
- }
- return result;
- }
- static PaError WdmSetMuxNodeProperty(HANDLE handle,
- ULONG nodeId,
- ULONG pinId)
- {
- PaError result = paNoError;
- KSNODEPROPERTY prop;
- prop.Property.Set = KSPROPSETID_Audio;
- prop.Property.Id = KSPROPERTY_AUDIO_MUX_SOURCE;
- prop.Property.Flags = KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_TOPOLOGY;
- prop.NodeId = nodeId;
- prop.Reserved = 0;
- result = WdmSyncIoctl(handle, IOCTL_KS_PROPERTY, &prop, sizeof(KSNODEPROPERTY), &pinId, sizeof(ULONG), NULL);
- return result;
- }
- /* Used when traversing topology for outputs */
- static const KSTOPOLOGY_CONNECTION* GetConnectionTo(const KSTOPOLOGY_CONNECTION* pFrom, PaWinWdmFilter* filter, int muxIdx)
- {
- unsigned i;
- const KSTOPOLOGY_CONNECTION* retval = NULL;
- const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1);
- (void)muxIdx;
- PA_DEBUG(("GetConnectionTo: Checking %u connections... (pFrom = %p)", filter->connections->Count, pFrom));
- for (i = 0; i < filter->connections->Count; ++i)
- {
- const KSTOPOLOGY_CONNECTION* pConn = connections + i;
- if (pConn == pFrom)
- continue;
- if (pConn->FromNode == pFrom->ToNode)
- {
- retval = pConn;
- break;
- }
- }
- PA_DEBUG(("GetConnectionTo: Returning %p\n", retval));
- return retval;
- }
- /* Used when traversing topology for inputs */
- static const KSTOPOLOGY_CONNECTION* GetConnectionFrom(const KSTOPOLOGY_CONNECTION* pTo, PaWinWdmFilter* filter, int muxIdx)
- {
- unsigned i;
- const KSTOPOLOGY_CONNECTION* retval = NULL;
- const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1);
- int muxCntr = 0;
- PA_DEBUG(("GetConnectionFrom: Checking %u connections... (pTo = %p)\n", filter->connections->Count, pTo));
- for (i = 0; i < filter->connections->Count; ++i)
- {
- const KSTOPOLOGY_CONNECTION* pConn = connections + i;
- if (pConn == pTo)
- continue;
- if (pConn->ToNode == pTo->FromNode)
- {
- if (muxIdx >= 0)
- {
- if (muxCntr < muxIdx)
- {
- ++muxCntr;
- continue;
- }
- }
- retval = pConn;
- break;
- }
- }
- PA_DEBUG(("GetConnectionFrom: Returning %p\n", retval));
- return retval;
- }
- static ULONG GetNumberOfConnectionsTo(const KSTOPOLOGY_CONNECTION* pTo, PaWinWdmFilter* filter)
- {
- ULONG retval = 0;
- unsigned i;
- const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1);
- PA_DEBUG(("GetNumberOfConnectionsTo: Checking %u connections...", filter->connections->Count));
- for (i = 0; i < filter->connections->Count; ++i)
- {
- const KSTOPOLOGY_CONNECTION* pConn = connections + i;
- if (pConn->ToNode == pTo->FromNode &&
- (pTo->FromNode != KSFILTER_NODE || pConn->ToNodePin == pTo->FromNodePin))
- {
- ++retval;
- }
- }
- return retval;
- }
- typedef const KSTOPOLOGY_CONNECTION *(*TFnGetConnection)(const KSTOPOLOGY_CONNECTION*, PaWinWdmFilter*, int);
- static const KSTOPOLOGY_CONNECTION* FindStartConnectionFrom(ULONG startPin, PaWinWdmFilter* filter)
- {
- unsigned i;
- const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1);
- PA_DEBUG(("FindStartConnectionFrom: Checking %u connections...", filter->connections->Count));
- for (i = 0; i < filter->connections->Count; ++i)
- {
- const KSTOPOLOGY_CONNECTION* pConn = connections + i;
- if (pConn->ToNode == KSFILTER_NODE && pConn->ToNodePin == startPin)
- {
- return pConn;
- }
- }
- assert(FALSE);
- return 0;
- }
- static const KSTOPOLOGY_CONNECTION* FindStartConnectionTo(ULONG startPin, PaWinWdmFilter* filter)
- {
- unsigned i;
- const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1);
- PA_DEBUG(("FindStartConnectionTo: Checking %u connections...", filter->connections->Count));
- for (i = 0; i < filter->connections->Count; ++i)
- {
- const KSTOPOLOGY_CONNECTION* pConn = connections + i;
- if (pConn->FromNode == KSFILTER_NODE && pConn->FromNodePin == startPin)
- {
- return pConn;
- }
- }
- assert(FALSE);
- return 0;
- }
- static ULONG GetConnectedPin(ULONG startPin, BOOL forward, PaWinWdmFilter* filter, int muxPosition, ULONG *muxInputPinId, ULONG *muxNodeId)
- {
- const KSTOPOLOGY_CONNECTION *conn = NULL;
- TFnGetConnection fnGetConnection = forward ? GetConnectionTo : GetConnectionFrom ;
- while (1)
- {
- if (conn == NULL)
- {
- conn = forward ? FindStartConnectionTo(startPin, filter) : FindStartConnectionFrom(startPin, filter);
- }
- else
- {
- conn = fnGetConnection(conn, filter, -1);
- }
- /* Handling case of erroneous connection list */
- if (conn == NULL)
- {
- break;
- }
- if (forward ? conn->ToNode == KSFILTER_NODE : conn->FromNode == KSFILTER_NODE)
- {
- return forward ? conn->ToNodePin : conn->FromNodePin;
- }
- else
- {
- PA_DEBUG(("GetConnectedPin: count=%d, forward=%d, muxPosition=%d\n", filter->nodes->Count, forward, muxPosition));
- if (filter->nodes->Count > 0 && !forward && muxPosition >= 0)
- {
- const GUID* nodes = (const GUID*)(filter->nodes + 1);
- if (IsEqualGUID(&nodes[conn->FromNode], &KSNODETYPE_MUX))
- {
- ULONG nConn = GetNumberOfConnectionsTo(conn, filter);
- conn = fnGetConnection(conn, filter, muxPosition);
- if (conn == NULL)
- {
- break;
- }
- if (muxInputPinId != 0)
- {
- *muxInputPinId = conn->ToNodePin;
- }
- if (muxNodeId != 0)
- {
- *muxNodeId = conn->ToNode;
- }
- }
- }
- }
- }
- return KSFILTER_NODE;
- }
- static void DumpConnectionsAndNodes(PaWinWdmFilter* filter)
- {
- unsigned i;
- const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1);
- const GUID* nodes = (const GUID*)(filter->nodes + 1);
- PA_DEBUG(("DumpConnectionsAndNodes: connections=%d, nodes=%d\n", filter->connections->Count, filter->nodes->Count));
- for (i=0; i < filter->connections->Count; ++i)
- {
- const KSTOPOLOGY_CONNECTION* pConn = connections + i;
- PA_DEBUG((" Connection: %u - FromNode=%u,FromPin=%u -> ToNode=%u,ToPin=%u\n",
- i,
- pConn->FromNode, pConn->FromNodePin,
- pConn->ToNode, pConn->ToNodePin
- ));
- }
- for (i=0; i < filter->nodes->Count; ++i)
- {
- const GUID* pConn = nodes + i;
- PA_DEBUG((" Node: %d - {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n",
- i,
- pConn->Data1, pConn->Data2, pConn->Data3,
- pConn->Data4[0], pConn->Data4[1],
- pConn->Data4[2], pConn->Data4[3],
- pConn->Data4[4], pConn->Data4[5],
- pConn->Data4[6], pConn->Data4[7]
- ));
- }
- }
- typedef struct __PaUsbTerminalGUIDToName
- {
- USHORT usbGUID;
- wchar_t name[64];
- } PaUsbTerminalGUIDToName;
- static const PaUsbTerminalGUIDToName kNames[] =
- {
- /* Types copied from: http://msdn.microsoft.com/en-us/library/ff537742(v=vs.85).aspx */
- /* Input terminal types */
- { 0x0201, L"Microphone" },
- { 0x0202, L"Desktop Microphone" },
- { 0x0203, L"Personal Microphone" },
- { 0x0204, L"Omni Directional Microphone" },
- { 0x0205, L"Microphone Array" },
- { 0x0206, L"Processing Microphone Array" },
- /* Output terminal types */
- { 0x0301, L"Speakers" },
- { 0x0302, L"Headphones" },
- { 0x0303, L"Head Mounted Display Audio" },
- { 0x0304, L"Desktop Speaker" },
- { 0x0305, L"Room Speaker" },
- { 0x0306, L"Communication Speaker" },
- { 0x0307, L"LFE Speakers" },
- /* External terminal types */
- { 0x0601, L"Analog" },
- { 0x0602, L"Digital" },
- { 0x0603, L"Line" },
- { 0x0604, L"Audio" },
- { 0x0605, L"SPDIF" },
- };
- static const unsigned kNamesCnt = sizeof(kNames)/sizeof(PaUsbTerminalGUIDToName);
- static int PaUsbTerminalGUIDToNameCmp(const void* lhs, const void* rhs)
- {
- const PaUsbTerminalGUIDToName* pL = (const PaUsbTerminalGUIDToName*)lhs;
- const PaUsbTerminalGUIDToName* pR = (const PaUsbTerminalGUIDToName*)rhs;
- return ((int)(pL->usbGUID) - (int)(pR->usbGUID));
- }
- static PaError GetNameFromCategory(const GUID* pGUID, BOOL input, wchar_t* name, unsigned length)
- {
- PaError result = paUnanticipatedHostError;
- USHORT usbTerminalGUID = (USHORT)(pGUID->Data1 - 0xDFF219E0);
- if (input && usbTerminalGUID >= 0x301 && usbTerminalGUID < 0x400)
- {
- /* Output terminal name for an input !? Set it to Line! */
- usbTerminalGUID = 0x603;
- }
- if (!input && usbTerminalGUID >= 0x201 && usbTerminalGUID < 0x300)
- {
- /* Input terminal name for an output !? Set it to Line! */
- usbTerminalGUID = 0x603;
- }
- if (usbTerminalGUID >= 0x201 && usbTerminalGUID < 0x713)
- {
- PaUsbTerminalGUIDToName s = { usbTerminalGUID };
- const PaUsbTerminalGUIDToName* ptr = bsearch(
- &s,
- kNames,
- kNamesCnt,
- sizeof(PaUsbTerminalGUIDToName),
- PaUsbTerminalGUIDToNameCmp
- );
- if (ptr != 0)
- {
- PA_DEBUG(("GetNameFromCategory: USB GUID %04X -> '%S'\n", usbTerminalGUID, ptr->name));
- if (name != NULL && length > 0)
- {
- int n = _snwprintf(name, length, L"%s", ptr->name);
- if (usbTerminalGUID >= 0x601 && usbTerminalGUID < 0x700)
- {
- _snwprintf(name + n, length - n, L" %s", (input ? L"In":L"Out"));
- }
- }
- result = paNoError;
- }
- }
- else
- {
- PaWinWDM_SetLastErrorInfo(result, "GetNameFromCategory: usbTerminalGUID = %04X ", usbTerminalGUID);
- }
- return result;
- }
- static BOOL IsFrequencyWithinRange(const KSDATARANGE_AUDIO* range, int frequency)
- {
- if (frequency < (int)range->MinimumSampleFrequency)
- return FALSE;
- if (frequency > (int)range->MaximumSampleFrequency)
- return FALSE;
- return TRUE;
- }
- static BOOL IsBitsWithinRange(const KSDATARANGE_AUDIO* range, int noOfBits)
- {
- if (noOfBits < (int)range->MinimumBitsPerSample)
- return FALSE;
- if (noOfBits > (int)range->MaximumBitsPerSample)
- return FALSE;
- return TRUE;
- }
- /* Note: Somewhat different order compared to WMME implementation, as we want to focus on fidelity first */
- static const int defaultSampleRateSearchOrder[] =
- { 44100, 48000, 88200, 96000, 192000, 32000, 24000, 22050, 16000, 12000, 11025, 9600, 8000 };
- static const int defaultSampleRateSearchOrderCount = sizeof(defaultSampleRateSearchOrder)/sizeof(defaultSampleRateSearchOrder[0]);
- static int DefaultSampleFrequencyIndex(const KSDATARANGE_AUDIO* range)
- {
- int i;
- for(i=0; i < defaultSampleRateSearchOrderCount; ++i)
- {
- int currentFrequency = defaultSampleRateSearchOrder[i];
- if (IsFrequencyWithinRange(range, currentFrequency))
- {
- return i;
- }
- }
- return -1;
- }
- /*
- Create a new pin object belonging to a filter
- The pin object holds all the configuration information about the pin
- before it is opened, and then the handle of the pin after is opened
- */
- static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, PaError* error)
- {
- PaWinWdmPin* pin;
- PaError result;
- unsigned long i;
- KSMULTIPLE_ITEM* item = NULL;
- KSIDENTIFIER* identifier;
- KSDATARANGE* dataRange;
- const ULONG streamingId = (parentFilter->devInfo.streamingType == Type_kWaveRT) ? KSINTERFACE_STANDARD_LOOPED_STREAMING : KSINTERFACE_STANDARD_STREAMING;
- int defaultSampleRateIndex = defaultSampleRateSearchOrderCount;
- PA_LOGE_;
- PA_DEBUG(("PinNew: Creating pin %d:\n",pinId));
- /* Allocate the new PIN object */
- pin = (PaWinWdmPin*)PaUtil_AllocateMemory( sizeof(PaWinWdmPin) );
- if( !pin )
- {
- result = paInsufficientMemory;
- goto error;
- }
- /* Zero the pin object */
- /* memset( (void*)pin, 0, sizeof(PaWinWdmPin) ); */
- pin->parentFilter = parentFilter;
- pin->pinId = pinId;
- /* Allocate a connect structure */
- pin->pinConnectSize = sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT_WAVEFORMATEX);
- pin->pinConnect = (KSPIN_CONNECT*)PaUtil_AllocateMemory( pin->pinConnectSize );
- if( !pin->pinConnect )
- {
- result = paInsufficientMemory;
- goto error;
- }
- /* Configure the connect structure with default values */
- pin->pinConnect->Interface.Set = KSINTERFACESETID_Standard;
- pin->pinConnect->Interface.Id = streamingId;
- pin->pinConnect->Interface.Flags = 0;
- pin->pinConnect->Medium.Set = KSMEDIUMSETID_Standard;
- pin->pinConnect->Medium.Id = KSMEDIUM_TYPE_ANYINSTANCE;
- pin->pinConnect->Medium.Flags = 0;
- pin->pinConnect->PinId = pinId;
- pin->pinConnect->PinToHandle = NULL;
- pin->pinConnect->Priority.PriorityClass = KSPRIORITY_NORMAL;
- pin->pinConnect->Priority.PrioritySubClass = 1;
- pin->ksDataFormatWfx = (KSDATAFORMAT_WAVEFORMATEX*)(pin->pinConnect + 1);
- pin->ksDataFormatWfx->DataFormat.FormatSize = sizeof(KSDATAFORMAT_WAVEFORMATEX);
- pin->ksDataFormatWfx->DataFormat.Flags = 0;
- pin->ksDataFormatWfx->DataFormat.Reserved = 0;
- pin->ksDataFormatWfx->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
- pin->ksDataFormatWfx->DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
- pin->ksDataFormatWfx->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
- pin->frameSize = 0; /* Unknown until we instantiate pin */
- /* Get the COMMUNICATION property */
- result = WdmGetPinPropertySimple(
- parentFilter->handle,
- pinId,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_COMMUNICATION,
- &pin->communication,
- sizeof(KSPIN_COMMUNICATION),
- NULL);
- if( result != paNoError )
- goto error;
- if( /*(pin->communication != KSPIN_COMMUNICATION_SOURCE) &&*/
- (pin->communication != KSPIN_COMMUNICATION_SINK) &&
- (pin->communication != KSPIN_COMMUNICATION_BOTH) )
- {
- PA_DEBUG(("PinNew: Not source/sink\n"));
- result = paInvalidDevice;
- goto error;
- }
- /* Get dataflow information */
- result = WdmGetPinPropertySimple(
- parentFilter->handle,
- pinId,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_DATAFLOW,
- &pin->dataFlow,
- sizeof(KSPIN_DATAFLOW),
- NULL);
- if( result != paNoError )
- goto error;
- /* Get the INTERFACE property list */
- result = WdmGetPinPropertyMulti(
- parentFilter->handle,
- pinId,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_INTERFACES,
- &item);
- if( result != paNoError )
- goto error;
- identifier = (KSIDENTIFIER*)(item+1);
- /* Check that at least one interface is STANDARD_STREAMING */
- result = paUnanticipatedHostError;
- for( i = 0; i < item->Count; i++ )
- {
- if( IsEqualGUID(&identifier[i].Set, &KSINTERFACESETID_Standard) && ( identifier[i].Id == streamingId ) )
- {
- result = paNoError;
- break;
- }
- }
- if( result != paNoError )
- {
- PA_DEBUG(("PinNew: No %s streaming\n", streamingId==KSINTERFACE_STANDARD_LOOPED_STREAMING?"looped":"standard"));
- goto error;
- }
- /* Don't need interfaces any more */
- PaUtil_FreeMemory( item );
- item = NULL;
- /* Get the MEDIUM properties list */
- result = WdmGetPinPropertyMulti(
- parentFilter->handle,
- pinId,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_MEDIUMS,
- &item);
- if( result != paNoError )
- goto error;
- identifier = (KSIDENTIFIER*)(item+1); /* Not actually necessary... */
- /* Check that at least one medium is STANDARD_DEVIO */
- result = paUnanticipatedHostError;
- for( i = 0; i < item->Count; i++ )
- {
- if( IsEqualGUID(&identifier[i].Set, &KSMEDIUMSETID_Standard) && ( identifier[i].Id == KSMEDIUM_STANDARD_DEVIO ) )
- {
- result = paNoError;
- break;
- }
- }
- if( result != paNoError )
- {
- PA_DEBUG(("No standard devio\n"));
- goto error;
- }
- /* Don't need mediums any more */
- PaUtil_FreeMemory( item );
- item = NULL;
- /* Get DATARANGES */
- result = WdmGetPinPropertyMulti(
- parentFilter->handle,
- pinId,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_DATARANGES,
- &pin->dataRangesItem);
- if( result != paNoError )
- goto error;
- pin->dataRanges = (KSDATARANGE*)(pin->dataRangesItem +1);
- /* Check that at least one datarange supports audio */
- result = paUnanticipatedHostError;
- dataRange = pin->dataRanges;
- pin->maxChannels = 0;
- pin->defaultSampleRate = 0;
- pin->formats = 0;
- PA_DEBUG(("PinNew: Checking %u no of dataranges...\n", pin->dataRangesItem->Count));
- for( i = 0; i < pin->dataRangesItem->Count; i++)
- {
- PA_DEBUG(("PinNew: DR major format %x\n",*(unsigned long*)(&(dataRange->MajorFormat))));
- /* Check that subformat is WAVEFORMATEX, PCM or WILDCARD */
- if( IS_VALID_WAVEFORMATEX_GUID(&dataRange->SubFormat) ||
- IsEqualGUID(&dataRange->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) ||
- IsEqualGUID(&dataRange->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) ||
- IsEqualGUID(&dataRange->SubFormat, &KSDATAFORMAT_SUBTYPE_WILDCARD) ||
- IsEqualGUID(&dataRange->MajorFormat, &KSDATAFORMAT_TYPE_AUDIO) )
- {
- int defaultIndex;
- result = paNoError;
- /* Record the maximum possible channels with this pin */
- if( ((KSDATARANGE_AUDIO*)dataRange)->MaximumChannels == (ULONG) -1 )
- {
- pin->maxChannels = MAXIMUM_NUMBER_OF_CHANNELS;
- }
- else if( (int) ((KSDATARANGE_AUDIO*)dataRange)->MaximumChannels > pin->maxChannels )
- {
- pin->maxChannels = (int) ((KSDATARANGE_AUDIO*)dataRange)->MaximumChannels;
- }
- PA_DEBUG(("PinNew: MaxChannel: %d\n",pin->maxChannels));
- /* Record the formats (bit depths) that are supported */
- if( IsBitsWithinRange((KSDATARANGE_AUDIO*)dataRange, 8) )
- {
- pin->formats |= paInt8;
- PA_DEBUG(("PinNew: Format PCM 8 bit supported\n"));
- }
- if( IsBitsWithinRange((KSDATARANGE_AUDIO*)dataRange, 16) )
- {
- pin->formats |= paInt16;
- PA_DEBUG(("PinNew: Format PCM 16 bit supported\n"));
- }
- if( IsBitsWithinRange((KSDATARANGE_AUDIO*)dataRange, 24) )
- {
- pin->formats |= paInt24;
- PA_DEBUG(("PinNew: Format PCM 24 bit supported\n"));
- }
- if( IsBitsWithinRange((KSDATARANGE_AUDIO*)dataRange, 32) )
- {
- if (IsEqualGUID(&dataRange->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
- {
- pin->formats |= paFloat32;
- PA_DEBUG(("PinNew: Format IEEE float 32 bit supported\n"));
- }
- else
- {
- pin->formats |= paInt32;
- PA_DEBUG(("PinNew: Format PCM 32 bit supported\n"));
- }
- }
- defaultIndex = DefaultSampleFrequencyIndex((KSDATARANGE_AUDIO*)dataRange);
- if (defaultIndex >= 0 && defaultIndex < defaultSampleRateIndex)
- {
- defaultSampleRateIndex = defaultIndex;
- }
- }
- dataRange = (KSDATARANGE*)( ((char*)dataRange) + dataRange->FormatSize);
- }
- if( result != paNoError )
- goto error;
- /* If none of the frequencies searched for are present, there's something seriously wrong */
- if (defaultSampleRateIndex == defaultSampleRateSearchOrderCount)
- {
- PA_DEBUG(("PinNew: No default sample rate found, skipping pin!\n"));
- PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "PinNew: No default sample rate found");
- result = paUnanticipatedHostError;
- goto error;
- }
- /* Set the default sample rate */
- pin->defaultSampleRate = defaultSampleRateSearchOrder[defaultSampleRateIndex];
- PA_DEBUG(("PinNew: Default sample rate = %d Hz\n", pin->defaultSampleRate));
- /* Get instance information */
- result = WdmGetPinPropertySimple(
- parentFilter->handle,
- pinId,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_CINSTANCES,
- &pin->instances,
- sizeof(KSPIN_CINSTANCES),
- NULL);
- if( result != paNoError )
- goto error;
- /* If WaveRT, check if pin supports notification mode */
- if (parentFilter->devInfo.streamingType == Type_kWaveRT)
- {
- BOOL bSupportsNotification = FALSE;
- if (PinQueryNotificationSupport(pin, &bSupportsNotification) == paNoError)
- {
- pin->pinKsSubType = bSupportsNotification ? SubType_kNotification : SubType_kPolled;
- }
- }
- /* Query pin name (which means we need to traverse to non IRP pin, via physical connection to topology filter pin, through
- its nodes to the endpoint pin, and get that ones name... phew...) */
- PA_DEBUG(("PinNew: Finding topology pin...\n"));
- {
- ULONG topoPinId = GetConnectedPin(pinId, (pin->dataFlow == KSPIN_DATAFLOW_IN), parentFilter, -1, NULL, NULL);
- const wchar_t kInputName[] = L"Input";
- const wchar_t kOutputName[] = L"Output";
- if (topoPinId != KSFILTER_NODE)
- {
- /* Get physical connection for topo pin */
- unsigned long cbBytes = 0;
- PA_DEBUG(("PinNew: Getting physical connection...\n"));
- result = WdmGetPinPropertySimple(parentFilter->handle,
- topoPinId,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_PHYSICALCONNECTION,
- 0,
- 0,
- &cbBytes
- );
- if (result != paNoError)
- {
- /* No physical connection -> there is no topology filter! So we get the name of the pin! */
- PA_DEBUG(("PinNew: No physical connection! Getting the pin name\n"));
- result = WdmGetPinPropertySimple(parentFilter->handle,
- topoPinId,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_NAME,
- pin->friendlyName,
- MAX_PATH,
- NULL);
- if (result != paNoError)
- {
- GUID category = {0};
- /* Get pin category information */
- result = WdmGetPinPropertySimple(parentFilter->handle,
- topoPinId,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_CATEGORY,
- &category,
- sizeof(GUID),
- NULL);
- if (result == paNoError)
- {
- result = GetNameFromCategory(&category, (pin->dataFlow == KSPIN_DATAFLOW_OUT), pin->friendlyName, MAX_PATH);
- }
- }
- /* Make sure pin gets a name here... */
- if (wcslen(pin->friendlyName) == 0)
- {
- wcscpy(pin->friendlyName, (pin->dataFlow == KSPIN_DATAFLOW_IN) ? kOutputName : kInputName);
- #ifdef UNICODE
- PA_DEBUG(("PinNew: Setting pin friendly name to '%s'\n", pin->friendlyName));
- #else
- PA_DEBUG(("PinNew: Setting pin friendly name to '%S'\n", pin->friendlyName));
- #endif
- }
- /* This is then == the endpoint pin */
- pin->endpointPinId = (pin->dataFlow == KSPIN_DATAFLOW_IN) ? pinId : topoPinId;
- }
- else
- {
- KSPIN_PHYSICALCONNECTION* pc = (KSPIN_PHYSICALCONNECTION*)PaUtil_AllocateMemory(cbBytes + 2);
- PA_DEBUG(("PinNew: Physical connection found!\n"));
- if (pc == NULL)
- {
- result = paInsufficientMemory;
- goto error;
- }
- result = WdmGetPinPropertySimple(parentFilter->handle,
- topoPinId,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_PHYSICALCONNECTION,
- pc,
- cbBytes,
- NULL
- );
- if (result == paNoError)
- {
- wchar_t symbLinkName[MAX_PATH];
- wcsncpy(symbLinkName, pc->SymbolicLinkName, MAX_PATH);
- if (symbLinkName[1] == TEXT('?'))
- {
- symbLinkName[1] = TEXT('\\');
- }
- if (pin->parentFilter->topologyFilter == NULL)
- {
- PA_DEBUG(("PinNew: Creating topology filter '%S'\n", symbLinkName));
- pin->parentFilter->topologyFilter = FilterNew(Type_kNotUsed, 0, symbLinkName, L"", &result);
- if (pin->parentFilter->topologyFilter == NULL)
- {
- PA_DEBUG(("PinNew: Failed creating topology filter\n"));
- result = paUnanticipatedHostError;
- PaWinWDM_SetLastErrorInfo(result, "Failed to create topology filter '%S'", symbLinkName);
- goto error;
- }
- /* Copy info so we have it in device info */
- wcsncpy(pin->parentFilter->devInfo.topologyPath, symbLinkName, MAX_PATH);
- }
- else
- {
- /* Must be the same */
- assert(wcscmp(symbLinkName, pin->parentFilter->topologyFilter->devInfo.filterPath) == 0);
- }
- PA_DEBUG(("PinNew: Opening topology filter..."));
- result = FilterUse(pin->parentFilter->topologyFilter);
- if (result == paNoError)
- {
- unsigned long endpointPinId;
- if (pin->dataFlow == KSPIN_DATAFLOW_IN)
- {
- /* The "endpointPinId" is what WASAPI looks at for pin names */
- GUID category = {0};
- PA_DEBUG(("PinNew: Checking for output endpoint pin id...\n"));
- endpointPinId = GetConnectedPin(pc->Pin, TRUE, pin->parentFilter->topologyFilter, -1, NULL, NULL);
- if (endpointPinId == KSFILTER_NODE)
- {
- result = paUnanticipatedHostError;
- PaWinWDM_SetLastErrorInfo(result, "Failed to get endpoint pin ID on topology filter!");
- goto error;
- }
- PA_DEBUG(("PinNew: Found endpoint pin id %u\n", endpointPinId));
- /* Get pin category information */
- result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle,
- endpointPinId,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_CATEGORY,
- &category,
- sizeof(GUID),
- NULL);
- if (result == paNoError)
- {
- #if !PA_WDMKS_USE_CATEGORY_FOR_PIN_NAMES
- wchar_t pinName[MAX_PATH];
- PA_DEBUG(("PinNew: Getting pin name property..."));
- /* Ok, try pin name also, and favor that if available */
- result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle,
- endpointPinId,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_NAME,
- pinName,
- MAX_PATH,
- NULL);
- if (result == paNoError && wcslen(pinName)>0)
- {
- wcsncpy(pin->friendlyName, pinName, MAX_PATH);
- }
- else
- #endif
- {
- result = GetNameFromCategory(&category, (pin->dataFlow == KSPIN_DATAFLOW_OUT), pin->friendlyName, MAX_PATH);
- }
- if (wcslen(pin->friendlyName) == 0)
- {
- wcscpy(pin->friendlyName, L"Output");
- }
- #ifdef UNICODE
- PA_DEBUG(("PinNew: Pin name '%s'\n", pin->friendlyName));
- #else
- PA_DEBUG(("PinNew: Pin name '%S'\n", pin->friendlyName));
- #endif
- }
- /* Set endpoint pin ID (this is the topology INPUT pin, since portmixer will always traverse the
- filter in audio streaming direction, see http://msdn.microsoft.com/en-us/library/windows/hardware/ff536331(v=vs.85).aspx
- for more information)
- */
- pin->endpointPinId = pc->Pin;
- }
- else
- {
- unsigned muxCount = 0;
- int muxPos = 0;
- /* Max 64 multiplexer inputs... sanity check :) */
- for (i = 0; i < 64; ++i)
- {
- ULONG muxNodeIdTest = (unsigned)-1;
- PA_DEBUG(("PinNew: Checking for input endpoint pin id (%d)...\n", i));
- endpointPinId = GetConnectedPin(pc->Pin,
- FALSE,
- pin->parentFilter->topologyFilter,
- (int)i,
- NULL,
- &muxNodeIdTest);
- if (endpointPinId == KSFILTER_NODE)
- {
- /* We're done */
- PA_DEBUG(("PinNew: Done with inputs.\n", endpointPinId));
- break;
- }
- else
- {
- /* The "endpointPinId" is what WASAPI looks at for pin names */
- GUID category = {0};
- PA_DEBUG(("PinNew: Found endpoint pin id %u\n", endpointPinId));
- /* Get pin category information */
- result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle,
- endpointPinId,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_CATEGORY,
- &category,
- sizeof(GUID),
- NULL);
- if (result == paNoError)
- {
- if (muxNodeIdTest == (unsigned)-1)
- {
- /* Ok, try pin name, and favor that if available */
- result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle,
- endpointPinId,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_NAME,
- pin->friendlyName,
- MAX_PATH,
- NULL);
- if (result != paNoError)
- {
- result = GetNameFromCategory(&category, TRUE, pin->friendlyName, MAX_PATH);
- }
- break;
- }
- else
- {
- result = GetNameFromCategory(&category, TRUE, NULL, 0);
- if (result == paNoError)
- {
- ++muxCount;
- }
- }
- }
- else
- {
- PA_DEBUG(("PinNew: Failed to get pin category"));
- }
- }
- }
- if (muxCount == 0)
- {
- pin->endpointPinId = endpointPinId;
- /* Make sure we get a name for the pin */
- if (wcslen(pin->friendlyName) == 0)
- {
- wcscpy(pin->friendlyName, kInputName);
- }
- #ifdef UNICODE
- PA_DEBUG(("PinNew: Input friendly name '%s'\n", pin->friendlyName));
- #else
- PA_DEBUG(("PinNew: Input friendly name '%S'\n", pin->friendlyName));
- #endif
- }
- else // muxCount > 0
- {
- PA_DEBUG(("PinNew: Setting up %u inputs\n", muxCount));
- /* Now we redo the operation once known how many multiplexer positions there are */
- pin->inputs = (PaWinWdmMuxedInput**)PaUtil_AllocateMemory(muxCount * sizeof(PaWinWdmMuxedInput*));
- if (pin->inputs == NULL)
- {
- FilterRelease(pin->parentFilter->topologyFilter);
- result = paInsufficientMemory;
- goto error;
- }
- pin->inputCount = muxCount;
- for (i = 0; i < muxCount; ++muxPos)
- {
- PA_DEBUG(("PinNew: Setting up input %u...\n", i));
- if (pin->inputs[i] == NULL)
- {
- pin->inputs[i] = (PaWinWdmMuxedInput*)PaUtil_AllocateMemory(sizeof(PaWinWdmMuxedInput));
- if (pin->inputs[i] == NULL)
- {
- FilterRelease(pin->parentFilter->topologyFilter);
- result = paInsufficientMemory;
- goto error;
- }
- }
- endpointPinId = GetConnectedPin(pc->Pin,
- FALSE,
- pin->parentFilter->topologyFilter,
- muxPos,
- &pin->inputs[i]->muxPinId,
- &pin->inputs[i]->muxNodeId);
- if (endpointPinId != KSFILTER_NODE)
- {
- /* The "endpointPinId" is what WASAPI looks at for pin names */
- GUID category = {0};
- /* Set input endpoint ID */
- pin->inputs[i]->endpointPinId = endpointPinId;
- /* Get pin category information */
- result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle,
- endpointPinId,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_CATEGORY,
- &category,
- sizeof(GUID),
- NULL);
- if (result == paNoError)
- {
- /* Try pin name first, and if that is not defined, use category instead */
- result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle,
- endpointPinId,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_NAME,
- pin->inputs[i]->friendlyName,
- MAX_PATH,
- NULL);
- if (result != paNoError)
- {
- result = GetNameFromCategory(&category, TRUE, pin->inputs[i]->friendlyName, MAX_PATH);
- if (result != paNoError)
- {
- /* Only specify name, let name hash in ScanDeviceInfos fix postfix enumerators */
- wcscpy(pin->inputs[i]->friendlyName, kInputName);
- }
- }
- #ifdef UNICODE
- PA_DEBUG(("PinNew: Input (%u) friendly name '%s'\n", i, pin->inputs[i]->friendlyName));
- #else
- PA_DEBUG(("PinNew: Input (%u) friendly name '%S'\n", i, pin->inputs[i]->friendlyName));
- #endif
- ++i;
- }
- }
- else
- {
- /* Should never come here! */
- assert(FALSE);
- }
- }
- }
- }
- }
- }
- PaUtil_FreeMemory(pc);
- }
- }
- else
- {
- PA_DEBUG(("PinNew: No topology pin id found. Bad...\n"));
- /* No TOPO pin id ??? This is bad. Ok, so we just say it is an input or output... */
- wcscpy(pin->friendlyName, (pin->dataFlow == KSPIN_DATAFLOW_IN) ? kOutputName : kInputName);
- }
- }
- /* Release topology filter if it has been used */
- if (pin->parentFilter->topologyFilter && pin->parentFilter->topologyFilter->handle != NULL)
- {
- PA_DEBUG(("PinNew: Releasing topology filter...\n"));
- FilterRelease(pin->parentFilter->topologyFilter);
- }
- /* Success */
- *error = paNoError;
- PA_DEBUG(("Pin created successfully\n"));
- PA_LOGL_;
- return pin;
- error:
- PA_DEBUG(("PinNew: Error %d\n", result));
- /*
- Error cleanup
- */
- PaUtil_FreeMemory( item );
- if( pin )
- {
- if (pin->parentFilter->topologyFilter && pin->parentFilter->topologyFilter->handle != NULL)
- {
- FilterRelease(pin->parentFilter->topologyFilter);
- }
- PaUtil_FreeMemory( pin->pinConnect );
- PaUtil_FreeMemory( pin->dataRangesItem );
- PaUtil_FreeMemory( pin );
- }
- *error = result;
- PA_LOGL_;
- return NULL;
- }
- /*
- Safely free all resources associated with the pin
- */
- static void PinFree(PaWinWdmPin* pin)
- {
- unsigned i;
- PA_LOGE_;
- if( pin )
- {
- PinClose(pin);
- if( pin->pinConnect )
- {
- PaUtil_FreeMemory( pin->pinConnect );
- }
- if( pin->dataRangesItem )
- {
- PaUtil_FreeMemory( pin->dataRangesItem );
- }
- if( pin->inputs )
- {
- for (i = 0; i < pin->inputCount; ++i)
- {
- PaUtil_FreeMemory( pin->inputs[i] );
- }
- PaUtil_FreeMemory( pin->inputs );
- }
- PaUtil_FreeMemory( pin );
- }
- PA_LOGL_;
- }
- /*
- If the pin handle is open, close it
- */
- static void PinClose(PaWinWdmPin* pin)
- {
- PA_LOGE_;
- if( pin == NULL )
- {
- PA_DEBUG(("Closing NULL pin!"));
- PA_LOGL_;
- return;
- }
- if( pin->handle != NULL )
- {
- PinSetState( pin, KSSTATE_PAUSE );
- PinSetState( pin, KSSTATE_STOP );
- CloseHandle( pin->handle );
- pin->handle = NULL;
- FilterRelease(pin->parentFilter);
- }
- PA_LOGL_;
- }
- /*
- Set the state of this (instantiated) pin
- */
- static PaError PinSetState(PaWinWdmPin* pin, KSSTATE state)
- {
- PaError result = paNoError;
- KSPROPERTY prop;
- PA_LOGE_;
- prop.Set = KSPROPSETID_Connection;
- prop.Id = KSPROPERTY_CONNECTION_STATE;
- prop.Flags = KSPROPERTY_TYPE_SET;
- if( pin == NULL )
- return paInternalError;
- if( pin->handle == NULL )
- return paInternalError;
- result = WdmSyncIoctl(pin->handle, IOCTL_KS_PROPERTY, &prop, sizeof(KSPROPERTY), &state, sizeof(KSSTATE), NULL);
- PA_LOGL_;
- return result;
- }
- static PaError PinInstantiate(PaWinWdmPin* pin)
- {
- PaError result;
- unsigned long createResult;
- KSALLOCATOR_FRAMING ksaf;
- KSALLOCATOR_FRAMING_EX ksafex;
- PA_LOGE_;
- if( pin == NULL )
- return paInternalError;
- if(!pin->pinConnect)
- return paInternalError;
- FilterUse(pin->parentFilter);
- createResult = FunctionKsCreatePin(
- pin->parentFilter->handle,
- pin->pinConnect,
- GENERIC_WRITE | GENERIC_READ,
- &pin->handle
- );
- PA_DEBUG(("Pin create result = 0x%08x\n",createResult));
- if( createResult != ERROR_SUCCESS )
- {
- FilterRelease(pin->parentFilter);
- pin->handle = NULL;
- switch (createResult)
- {
- case ERROR_INVALID_PARAMETER:
- /* First case when pin actually don't support the format */
- return paSampleFormatNotSupported;
- case ERROR_BAD_COMMAND:
- /* Case when pin is occupied (by another application) */
- return paDeviceUnavailable;
- default:
- /* All other cases */
- return paInvalidDevice;
- }
- }
- if (pin->parentFilter->devInfo.streamingType == Type_kWaveCyclic)
- {
- /* Framing size query only valid for WaveCyclic devices */
- result = WdmGetPropertySimple(
- pin->handle,
- &KSPROPSETID_Connection,
- KSPROPERTY_CONNECTION_ALLOCATORFRAMING,
- &ksaf,
- sizeof(ksaf));
- if( result != paNoError )
- {
- result = WdmGetPropertySimple(
- pin->handle,
- &KSPROPSETID_Connection,
- KSPROPERTY_CONNECTION_ALLOCATORFRAMING_EX,
- &ksafex,
- sizeof(ksafex));
- if( result == paNoError )
- {
- pin->frameSize = ksafex.FramingItem[0].FramingRange.Range.MinFrameSize;
- }
- }
- else
- {
- pin->frameSize = ksaf.FrameSize;
- }
- }
- PA_LOGL_;
- return paNoError;
- }
- static PaError PinSetFormat(PaWinWdmPin* pin, const WAVEFORMATEX* format)
- {
- unsigned long size;
- void* newConnect;
- PA_LOGE_;
- if( pin == NULL )
- return paInternalError;
- if( format == NULL )
- return paInternalError;
- size = GetWfexSize(format) + sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT_WAVEFORMATEX) - sizeof(WAVEFORMATEX);
- if( pin->pinConnectSize != size )
- {
- newConnect = PaUtil_AllocateMemory( size );
- if( newConnect == NULL )
- return paInsufficientMemory;
- memcpy( newConnect, (void*)pin->pinConnect, min(pin->pinConnectSize,size) );
- PaUtil_FreeMemory( pin->pinConnect );
- pin->pinConnect = (KSPIN_CONNECT*)newConnect;
- pin->pinConnectSize = size;
- pin->ksDataFormatWfx = (KSDATAFORMAT_WAVEFORMATEX*)((KSPIN_CONNECT*)newConnect + 1);
- pin->ksDataFormatWfx->DataFormat.FormatSize = size - sizeof(KSPIN_CONNECT);
- }
- memcpy( (void*)&(pin->ksDataFormatWfx->WaveFormatEx), format, GetWfexSize(format) );
- pin->ksDataFormatWfx->DataFormat.SampleSize = (unsigned short)(format->nChannels * (format->wBitsPerSample / 8));
- PA_LOGL_;
- return paNoError;
- }
- static PaError PinIsFormatSupported(PaWinWdmPin* pin, const WAVEFORMATEX* format)
- {
- KSDATARANGE_AUDIO* dataRange;
- unsigned long count;
- GUID guid = DYNAMIC_GUID( DEFINE_WAVEFORMATEX_GUID(format->wFormatTag) );
- PaError result = paInvalidDevice;
- const WAVEFORMATEXTENSIBLE* pFormatExt = (format->wFormatTag == WAVE_FORMAT_EXTENSIBLE) ? (const WAVEFORMATEXTENSIBLE*)format : 0;
- PA_LOGE_;
- if( pFormatExt != 0 )
- {
- guid = pFormatExt->SubFormat;
- }
- dataRange = (KSDATARANGE_AUDIO*)pin->dataRanges;
- for(count = 0;
- count<pin->dataRangesItem->Count;
- count++,
- dataRange = (KSDATARANGE_AUDIO*)( ((char*)dataRange) + dataRange->DataRange.FormatSize)) /* Need to update dataRange here, due to 'continue' !! */
- {
- /* Check major format*/
- if (!(IsEqualGUID(&(dataRange->DataRange.MajorFormat), &KSDATAFORMAT_TYPE_AUDIO) ||
- IsEqualGUID(&(dataRange->DataRange.MajorFormat), &KSDATAFORMAT_TYPE_WILDCARD)))
- {
- continue;
- }
- /* This is an audio or wildcard datarange... */
- if (! (IsEqualGUID(&(dataRange->DataRange.SubFormat), &KSDATAFORMAT_SUBTYPE_WILDCARD) ||
- IsEqualGUID(&(dataRange->DataRange.SubFormat), &KSDATAFORMAT_SUBTYPE_PCM) ||
- IsEqualGUID(&(dataRange->DataRange.SubFormat), &guid) ))
- {
- continue;
- }
- /* Check specifier... */
- if (! (IsEqualGUID(&(dataRange->DataRange.Specifier), &KSDATAFORMAT_SPECIFIER_WILDCARD) ||
- IsEqualGUID(&(dataRange->DataRange.Specifier), &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)) )
- {
- continue;
- }
- PA_DEBUG(("Pin:%x, DataRange:%d\n",(void*)pin,count));
- PA_DEBUG(("\tFormatSize:%d, SampleSize:%d\n",dataRange->DataRange.FormatSize,dataRange->DataRange.SampleSize));
- PA_DEBUG(("\tMaxChannels:%d\n",dataRange->MaximumChannels));
- PA_DEBUG(("\tBits:%d-%d\n",dataRange->MinimumBitsPerSample,dataRange->MaximumBitsPerSample));
- PA_DEBUG(("\tSampleRate:%d-%d\n",dataRange->MinimumSampleFrequency,dataRange->MaximumSampleFrequency));
- if( dataRange->MaximumChannels != (ULONG)-1 &&
- dataRange->MaximumChannels < format->nChannels )
- {
- result = paInvalidChannelCount;
- continue;
- }
- if (pFormatExt != 0)
- {
- if ( dataRange->MinimumBitsPerSample > pFormatExt->Samples.wValidBitsPerSample )
- {
- result = paSampleFormatNotSupported;
- continue;
- }
- if ( dataRange->MaximumBitsPerSample < pFormatExt->Samples.wValidBitsPerSample )
- {
- result = paSampleFormatNotSupported;
- continue;
- }
- }
- else
- {
- if( dataRange->MinimumBitsPerSample > format->wBitsPerSample )
- {
- result = paSampleFormatNotSupported;
- continue;
- }
- if( dataRange->MaximumBitsPerSample < format->wBitsPerSample )
- {
- result = paSampleFormatNotSupported;
- continue;
- }
- }
- if( dataRange->MinimumSampleFrequency > format->nSamplesPerSec )
- {
- result = paInvalidSampleRate;
- continue;
- }
- if( dataRange->MaximumSampleFrequency < format->nSamplesPerSec )
- {
- result = paInvalidSampleRate;
- continue;
- }
- /* Success! */
- result = paNoError;
- break;
- }
- PA_LOGL_;
- return result;
- }
- static PaError PinQueryNotificationSupport(PaWinWdmPin* pPin, BOOL* pbResult)
- {
- PaError result = paNoError;
- KSPROPERTY propIn;
- propIn.Set = KSPROPSETID_RtAudio;
- propIn.Id = 8; /* = KSPROPERTY_RTAUDIO_QUERY_NOTIFICATION_SUPPORT */
- propIn.Flags = KSPROPERTY_TYPE_GET;
- result = WdmSyncIoctl(pPin->handle, IOCTL_KS_PROPERTY,
- &propIn,
- sizeof(KSPROPERTY),
- pbResult,
- sizeof(BOOL),
- NULL);
- if (result != paNoError)
- {
- PA_DEBUG(("Failed PinQueryNotificationSupport\n"));
- }
- return result;
- }
- static PaError PinGetBufferWithNotification(PaWinWdmPin* pPin, void** pBuffer, DWORD* pRequestedBufSize, BOOL* pbCallMemBarrier)
- {
- PaError result = paNoError;
- KSRTAUDIO_BUFFER_PROPERTY_WITH_NOTIFICATION propIn;
- KSRTAUDIO_BUFFER propOut;
- propIn.BaseAddress = 0;
- propIn.NotificationCount = 2;
- propIn.RequestedBufferSize = *pRequestedBufSize;
- propIn.Property.Set = KSPROPSETID_RtAudio;
- propIn.Property.Id = KSPROPERTY_RTAUDIO_BUFFER_WITH_NOTIFICATION;
- propIn.Property.Flags = KSPROPERTY_TYPE_GET;
- result = WdmSyncIoctl(pPin->handle, IOCTL_KS_PROPERTY,
- &propIn,
- sizeof(KSRTAUDIO_BUFFER_PROPERTY_WITH_NOTIFICATION),
- &propOut,
- sizeof(KSRTAUDIO_BUFFER),
- NULL);
- if (result == paNoError)
- {
- *pBuffer = propOut.BufferAddress;
- *pRequestedBufSize = propOut.ActualBufferSize;
- *pbCallMemBarrier = propOut.CallMemoryBarrier;
- }
- else
- {
- PA_DEBUG(("Failed to get buffer with notification\n"));
- }
- return result;
- }
- static PaError PinGetBufferWithoutNotification(PaWinWdmPin* pPin, void** pBuffer, DWORD* pRequestedBufSize, BOOL* pbCallMemBarrier)
- {
- PaError result = paNoError;
- KSRTAUDIO_BUFFER_PROPERTY propIn;
- KSRTAUDIO_BUFFER propOut;
- propIn.BaseAddress = NULL;
- propIn.RequestedBufferSize = *pRequestedBufSize;
- propIn.Property.Set = KSPROPSETID_RtAudio;
- propIn.Property.Id = KSPROPERTY_RTAUDIO_BUFFER;
- propIn.Property.Flags = KSPROPERTY_TYPE_GET;
- result = WdmSyncIoctl(pPin->handle, IOCTL_KS_PROPERTY,
- &propIn,
- sizeof(KSRTAUDIO_BUFFER_PROPERTY),
- &propOut,
- sizeof(KSRTAUDIO_BUFFER),
- NULL);
- if (result == paNoError)
- {
- *pBuffer = propOut.BufferAddress;
- *pRequestedBufSize = propOut.ActualBufferSize;
- *pbCallMemBarrier = propOut.CallMemoryBarrier;
- }
- else
- {
- PA_DEBUG(("Failed to get buffer without notification\n"));
- }
- return result;
- }
- /* greatest common divisor - PGCD in French */
- static unsigned long PaWinWDMGCD( unsigned long a, unsigned long b )
- {
- return (b==0) ? a : PaWinWDMGCD( b, a%b);
- }
- /* This function will handle getting the cyclic buffer from a WaveRT driver. Certain WaveRT drivers needs to have
- requested buffer size on multiples of 128 bytes:
- */
- static PaError PinGetBuffer(PaWinWdmPin* pPin, void** pBuffer, DWORD* pRequestedBufSize, BOOL* pbCallMemBarrier)
- {
- PaError result = paNoError;
- while (1)
- {
- if (pPin->pinKsSubType != SubType_kPolled)
- {
- /* In case of unknown (or notification), we try both modes */
- result = PinGetBufferWithNotification(pPin, pBuffer, pRequestedBufSize, pbCallMemBarrier);
- if (result == paNoError)
- {
- PA_DEBUG(("PinGetBuffer: SubType_kNotification\n"));
- pPin->pinKsSubType = SubType_kNotification;
- break;
- }
- }
- result = PinGetBufferWithoutNotification(pPin, pBuffer, pRequestedBufSize, pbCallMemBarrier);
- if (result == paNoError)
- {
- PA_DEBUG(("PinGetBuffer: SubType_kPolled\n"));
- pPin->pinKsSubType = SubType_kPolled;
- break;
- }
- /* Check if requested size is on a 128 byte boundary */
- if (((*pRequestedBufSize) % 128UL) == 0)
- {
- PA_DEBUG(("Buffer size on 128 byte boundary, still fails :(\n"));
- /* Ok, can't do much more */
- break;
- }
- else
- {
- /* Compute LCM so we know which sizes are on a 128 byte boundary */
- const unsigned gcd = PaWinWDMGCD(128UL, pPin->ksDataFormatWfx->WaveFormatEx.nBlockAlign);
- const unsigned lcm = (128UL * pPin->ksDataFormatWfx->WaveFormatEx.nBlockAlign) / gcd;
- DWORD dwOldSize = *pRequestedBufSize;
- /* Align size to (next larger) LCM byte boundary, and then we try again. Note that LCM is not necessarily a
- power of 2. */
- *pRequestedBufSize = ((*pRequestedBufSize + lcm - 1) / lcm) * lcm;
- PA_DEBUG(("Adjusting buffer size from %u to %u bytes (128 byte boundary, LCM=%u)\n", dwOldSize, *pRequestedBufSize, lcm));
- }
- }
- return result;
- }
- static PaError PinRegisterPositionRegister(PaWinWdmPin* pPin)
- {
- PaError result = paNoError;
- KSRTAUDIO_HWREGISTER_PROPERTY propIn;
- KSRTAUDIO_HWREGISTER propOut;
- PA_LOGE_;
- propIn.BaseAddress = NULL;
- propIn.Property.Set = KSPROPSETID_RtAudio;
- propIn.Property.Id = KSPROPERTY_RTAUDIO_POSITIONREGISTER;
- propIn.Property.Flags = KSPROPERTY_TYPE_GET;
- result = WdmSyncIoctl(pPin->handle, IOCTL_KS_PROPERTY,
- &propIn,
- sizeof(KSRTAUDIO_HWREGISTER_PROPERTY),
- &propOut,
- sizeof(KSRTAUDIO_HWREGISTER),
- NULL);
- if (result == paNoError)
- {
- pPin->positionRegister = (ULONG*)propOut.Register;
- }
- else
- {
- PA_DEBUG(("Failed to register position register\n"));
- }
- PA_LOGL_;
- return result;
- }
- static PaError PinRegisterNotificationHandle(PaWinWdmPin* pPin, HANDLE handle)
- {
- PaError result = paNoError;
- KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY prop;
- PA_LOGE_;
- prop.NotificationEvent = handle;
- prop.Property.Set = KSPROPSETID_RtAudio;
- prop.Property.Id = KSPROPERTY_RTAUDIO_REGISTER_NOTIFICATION_EVENT;
- prop.Property.Flags = KSPROPERTY_TYPE_GET;
- result = WdmSyncIoctl(pPin->handle,
- IOCTL_KS_PROPERTY,
- &prop,
- sizeof(KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY),
- &prop,
- sizeof(KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY),
- NULL);
- if (result != paNoError) {
- PA_DEBUG(("Failed to register notification handle 0x%08X\n", handle));
- }
- PA_LOGL_;
- return result;
- }
- static PaError PinUnregisterNotificationHandle(PaWinWdmPin* pPin, HANDLE handle)
- {
- PaError result = paNoError;
- KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY prop;
- PA_LOGE_;
- if (handle != NULL)
- {
- prop.NotificationEvent = handle;
- prop.Property.Set = KSPROPSETID_RtAudio;
- prop.Property.Id = KSPROPERTY_RTAUDIO_UNREGISTER_NOTIFICATION_EVENT;
- prop.Property.Flags = KSPROPERTY_TYPE_GET;
- result = WdmSyncIoctl(pPin->handle,
- IOCTL_KS_PROPERTY,
- &prop,
- sizeof(KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY),
- &prop,
- sizeof(KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY),
- NULL);
- if (result != paNoError) {
- PA_DEBUG(("Failed to unregister notification handle 0x%08X\n", handle));
- }
- }
- PA_LOGL_;
- return result;
- }
- static PaError PinGetHwLatency(PaWinWdmPin* pPin, ULONG* pFifoSize, ULONG* pChipsetDelay, ULONG* pCodecDelay)
- {
- PaError result = paNoError;
- KSPROPERTY propIn;
- KSRTAUDIO_HWLATENCY propOut;
- PA_LOGE_;
- propIn.Set = KSPROPSETID_RtAudio;
- propIn.Id = KSPROPERTY_RTAUDIO_HWLATENCY;
- propIn.Flags = KSPROPERTY_TYPE_GET;
- result = WdmSyncIoctl(pPin->handle, IOCTL_KS_PROPERTY,
- &propIn,
- sizeof(KSPROPERTY),
- &propOut,
- sizeof(KSRTAUDIO_HWLATENCY),
- NULL);
- if (result == paNoError)
- {
- *pFifoSize = propOut.FifoSize;
- *pChipsetDelay = propOut.ChipsetDelay;
- *pCodecDelay = propOut.CodecDelay;
- }
- else
- {
- PA_DEBUG(("Failed to retrieve hardware FIFO size!\n"));
- }
- PA_LOGL_;
- return result;
- }
- /* This one is used for WaveRT */
- static PaError PinGetAudioPositionDirect(PaWinWdmPin* pPin, ULONG* pPosition)
- {
- *pPosition = (*pPin->positionRegister);
- return paNoError;
- }
- /* This one also, but in case the driver hasn't implemented memory mapped access to the position register */
- static PaError PinGetAudioPositionViaIOCTL(PaWinWdmPin* pPin, ULONG* pPosition)
- {
- PaError result = paNoError;
- KSPROPERTY propIn;
- KSAUDIO_POSITION propOut;
- PA_LOGE_;
- propIn.Set = KSPROPSETID_Audio;
- propIn.Id = KSPROPERTY_AUDIO_POSITION;
- propIn.Flags = KSPROPERTY_TYPE_GET;
- result = WdmSyncIoctl(pPin->handle,
- IOCTL_KS_PROPERTY,
- &propIn, sizeof(KSPROPERTY),
- &propOut, sizeof(KSAUDIO_POSITION),
- NULL);
- if (result == paNoError)
- {
- *pPosition = (ULONG)(propOut.PlayOffset);
- }
- else
- {
- PA_DEBUG(("Failed to get audio position!\n"));
- }
- PA_LOGL_;
- return result;
- }
- /***********************************************************************************************/
- /**
- * Create a new filter object.
- */
- static PaWinWdmFilter* FilterNew( PaWDMKSType type, DWORD devNode, const wchar_t* filterName, const wchar_t* friendlyName, PaError* error )
- {
- PaWinWdmFilter* filter = 0;
- PaError result;
- /* Allocate the new filter object */
- filter = (PaWinWdmFilter*)PaUtil_AllocateMemory( sizeof(PaWinWdmFilter) );
- if( !filter )
- {
- result = paInsufficientMemory;
- goto error;
- }
- PA_DEBUG(("FilterNew: Creating filter '%S'\n", friendlyName));
- /* Set type flag */
- filter->devInfo.streamingType = type;
- /* Store device node */
- filter->deviceNode = devNode;
- /* Zero the filter object - done by AllocateMemory */
- /* memset( (void*)filter, 0, sizeof(PaWinWdmFilter) ); */
- /* Copy the filter name */
- wcsncpy(filter->devInfo.filterPath, filterName, MAX_PATH);
- /* Copy the friendly name */
- wcsncpy(filter->friendlyName, friendlyName, MAX_PATH);
- PA_DEBUG(("FilterNew: Opening filter...\n", friendlyName));
- /* Open the filter handle */
- result = FilterUse(filter);
- if( result != paNoError )
- {
- goto error;
- }
- /* Get pin count */
- result = WdmGetPinPropertySimple
- (
- filter->handle,
- 0,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_CTYPES,
- &filter->pinCount,
- sizeof(filter->pinCount),
- NULL);
- if( result != paNoError)
- {
- goto error;
- }
- /* Get connections & nodes for filter */
- result = WdmGetPropertyMulti(
- filter->handle,
- &KSPROPSETID_Topology,
- KSPROPERTY_TOPOLOGY_CONNECTIONS,
- &filter->connections);
- if( result != paNoError)
- {
- goto error;
- }
- result = WdmGetPropertyMulti(
- filter->handle,
- &KSPROPSETID_Topology,
- KSPROPERTY_TOPOLOGY_NODES,
- &filter->nodes);
- if( result != paNoError)
- {
- goto error;
- }
- /* For debugging purposes */
- DumpConnectionsAndNodes(filter);
- /* Get product GUID (it might not be supported) */
- {
- KSCOMPONENTID compId;
- if (WdmGetPropertySimple(filter->handle, &KSPROPSETID_General, KSPROPERTY_GENERAL_COMPONENTID, &compId, sizeof(KSCOMPONENTID)) == paNoError)
- {
- filter->devInfo.deviceProductGuid = compId.Product;
- }
- }
- /* This section is not executed for topology filters */
- if (type != Type_kNotUsed)
- {
- /* Initialize the pins */
- result = FilterInitializePins(filter);
- if( result != paNoError)
- {
- goto error;
- }
- }
- /* Close the filter handle for now
- * It will be opened later when needed */
- FilterRelease(filter);
- *error = paNoError;
- return filter;
- error:
- PA_DEBUG(("FilterNew: Error %d\n", result));
- /*
- Error cleanup
- */
- FilterFree(filter);
- *error = result;
- return NULL;
- }
- /**
- * Add reference to filter
- */
- static void FilterAddRef( PaWinWdmFilter* filter )
- {
- if (filter != 0)
- {
- filter->filterRefCount++;
- }
- }
- /**
- * Initialize the pins of the filter. This is separated from FilterNew because this might fail if there is another
- * process using the pin(s).
- */
- PaError FilterInitializePins( PaWinWdmFilter* filter )
- {
- PaError result = paNoError;
- int pinId;
- if (filter->devInfo.streamingType == Type_kNotUsed)
- return paNoError;
- if (filter->pins != NULL)
- return paNoError;
- /* Allocate pointer array to hold the pins */
- filter->pins = (PaWinWdmPin**)PaUtil_AllocateMemory( sizeof(PaWinWdmPin*) * filter->pinCount );
- if( !filter->pins )
- {
- result = paInsufficientMemory;
- goto error;
- }
- /* Create all the pins we can */
- for(pinId = 0; pinId < filter->pinCount; pinId++)
- {
- /* Create the pin with this Id */
- PaWinWdmPin* newPin;
- newPin = PinNew(filter, pinId, &result);
- if( result == paInsufficientMemory )
- goto error;
- if( newPin != NULL )
- {
- filter->pins[pinId] = newPin;
- ++filter->validPinCount;
- }
- }
- if (filter->validPinCount == 0)
- {
- result = paDeviceUnavailable;
- goto error;
- }
- return paNoError;
- error:
- if (filter->pins)
- {
- for (pinId = 0; pinId < filter->pinCount; ++pinId)
- {
- if (filter->pins[pinId])
- {
- PaUtil_FreeMemory(filter->pins[pinId]);
- filter->pins[pinId] = 0;
- }
- }
- PaUtil_FreeMemory( filter->pins );
- filter->pins = 0;
- }
- return result;
- }
- /**
- * Free a previously created filter
- */
- static void FilterFree(PaWinWdmFilter* filter)
- {
- int pinId;
- PA_LOGL_;
- if( filter )
- {
- if (--filter->filterRefCount > 0)
- {
- /* Ok, a stream has a ref count to this filter */
- return;
- }
- if (filter->topologyFilter)
- {
- FilterFree(filter->topologyFilter);
- filter->topologyFilter = 0;
- }
- if ( filter->pins )
- {
- for( pinId = 0; pinId < filter->pinCount; pinId++ )
- PinFree(filter->pins[pinId]);
- PaUtil_FreeMemory( filter->pins );
- filter->pins = 0;
- }
- if( filter->connections )
- {
- PaUtil_FreeMemory(filter->connections);
- filter->connections = 0;
- }
- if( filter->nodes )
- {
- PaUtil_FreeMemory(filter->nodes);
- filter->nodes = 0;
- }
- if( filter->handle )
- CloseHandle( filter->handle );
- PaUtil_FreeMemory( filter );
- }
- PA_LOGE_;
- }
- /**
- * Reopen the filter handle if necessary so it can be used
- **/
- static PaError FilterUse(PaWinWdmFilter* filter)
- {
- assert( filter );
- PA_LOGE_;
- if( filter->handle == NULL )
- {
- /* Open the filter */
- filter->handle = CreateFileW(
- filter->devInfo.filterPath,
- GENERIC_READ | GENERIC_WRITE,
- 0,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
- NULL);
- if( filter->handle == NULL )
- {
- return paDeviceUnavailable;
- }
- }
- filter->usageCount++;
- PA_LOGL_;
- return paNoError;
- }
- /**
- * Release the filter handle if nobody is using it
- **/
- static void FilterRelease(PaWinWdmFilter* filter)
- {
- assert( filter );
- assert( filter->usageCount > 0 );
- PA_LOGE_;
- /* Check first topology filter, if used */
- if (filter->topologyFilter != NULL && filter->topologyFilter->handle != NULL)
- {
- FilterRelease(filter->topologyFilter);
- }
- filter->usageCount--;
- if( filter->usageCount == 0 )
- {
- if( filter->handle != NULL )
- {
- CloseHandle( filter->handle );
- filter->handle = NULL;
- }
- }
- PA_LOGL_;
- }
- /**
- * Create a render or playback pin using the supplied format
- **/
- static PaWinWdmPin* FilterCreatePin(PaWinWdmFilter* filter,
- int pinId,
- const WAVEFORMATEX* wfex,
- PaError* error)
- {
- PaError result = paNoError;
- PaWinWdmPin* pin = NULL;
- assert( filter );
- assert( pinId < filter->pinCount );
- pin = filter->pins[pinId];
- assert( pin );
- result = PinSetFormat(pin,wfex);
- if( result == paNoError )
- {
- result = PinInstantiate(pin);
- }
- *error = result;
- return result == paNoError ? pin : 0;
- }
- static const wchar_t kUsbPrefix[] = L"\\\\?\\USB";
- static BOOL IsUSBDevice(const wchar_t* devicePath)
- {
- /* Alex Lessard pointed out that different devices might present the device path with
- lower case letters. */
- return (_wcsnicmp(devicePath, kUsbPrefix, sizeof(kUsbPrefix)/sizeof(kUsbPrefix[0]) ) == 0);
- }
- /* This should make it more language tolerant, I hope... */
- static const wchar_t kUsbNamePrefix[] = L"USB Audio";
- static BOOL IsNameUSBAudioDevice(const wchar_t* friendlyName)
- {
- return (_wcsnicmp(friendlyName, kUsbNamePrefix, sizeof(kUsbNamePrefix)/sizeof(kUsbNamePrefix[0])) == 0);
- }
- typedef enum _tag_EAlias
- {
- Alias_kRender = (1<<0),
- Alias_kCapture = (1<<1),
- Alias_kRealtime = (1<<2),
- } EAlias;
- /* Trim whitespace from string */
- static void TrimString(wchar_t* str, size_t length)
- {
- wchar_t* s = str;
- wchar_t* e = 0;
- /* Find start of string */
- while (iswspace(*s)) ++s;
- e=s+min(length,wcslen(s))-1;
- /* Find end of string */
- while(e>s && iswspace(*e)) --e;
- ++e;
- length = e - s;
- memmove(str, s, length * sizeof(wchar_t));
- str[length] = 0;
- }
- /**
- * Build the list of available filters
- * Use the SetupDi API to enumerate all devices in the KSCATEGORY_AUDIO which
- * have a KSCATEGORY_RENDER or KSCATEGORY_CAPTURE alias. For each of these
- * devices initialise a PaWinWdmFilter structure by calling our NewFilter()
- * function. We enumerate devices twice, once to count how many there are,
- * and once to initialize the PaWinWdmFilter structures.
- *
- * Vista and later: Also check KSCATEGORY_REALTIME for WaveRT devices.
- */
- //PaError BuildFilterList( PaWinWdmHostApiRepresentation* wdmHostApi, int* noOfPaDevices )
- PaWinWdmFilter** BuildFilterList( int* pFilterCount, int* pNoOfPaDevices, PaError* pResult )
- {
- PaWinWdmFilter** ppFilters = NULL;
- HDEVINFO handle = NULL;
- int device;
- int invalidDevices;
- int slot;
- SP_DEVICE_INTERFACE_DATA interfaceData;
- SP_DEVICE_INTERFACE_DATA aliasData;
- SP_DEVINFO_DATA devInfoData;
- int noError;
- const int sizeInterface = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + (MAX_PATH * sizeof(WCHAR));
- unsigned char interfaceDetailsArray[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + (MAX_PATH * sizeof(WCHAR))];
- SP_DEVICE_INTERFACE_DETAIL_DATA_W* devInterfaceDetails = (SP_DEVICE_INTERFACE_DETAIL_DATA_W*)interfaceDetailsArray;
- const GUID* category = (const GUID*)&KSCATEGORY_AUDIO;
- const GUID* alias_render = (const GUID*)&KSCATEGORY_RENDER;
- const GUID* alias_capture = (const GUID*)&KSCATEGORY_CAPTURE;
- const GUID* category_realtime = (const GUID*)&KSCATEGORY_REALTIME;
- DWORD aliasFlags;
- PaWDMKSType streamingType;
- int filterCount = 0;
- int noOfPaDevices = 0;
- PA_LOGE_;
- assert(pFilterCount != NULL);
- assert(pNoOfPaDevices != NULL);
- assert(pResult != NULL);
- devInterfaceDetails->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
- *pFilterCount = 0;
- *pNoOfPaDevices = 0;
- /* Open a handle to search for devices (filters) */
- handle = SetupDiGetClassDevs(category,NULL,NULL,DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
- if( handle == INVALID_HANDLE_VALUE )
- {
- *pResult = paUnanticipatedHostError;
- return NULL;
- }
- PA_DEBUG(("Setup called\n"));
- /* First let's count the number of devices so we can allocate a list */
- invalidDevices = 0;
- for( device = 0;;device++ )
- {
- interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
- interfaceData.Reserved = 0;
- aliasData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
- aliasData.Reserved = 0;
- noError = SetupDiEnumDeviceInterfaces(handle,NULL,category,device,&interfaceData);
- PA_DEBUG(("Enum called\n"));
- if( !noError )
- break; /* No more devices */
- /* Check this one has the render or capture alias */
- aliasFlags = 0;
- noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_render,&aliasData);
- PA_DEBUG(("noError = %d\n",noError));
- if(noError)
- {
- if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED)))
- {
- PA_DEBUG(("Device %d has render alias\n",device));
- aliasFlags |= Alias_kRender; /* Has render alias */
- }
- else
- {
- PA_DEBUG(("Device %d has no render alias\n",device));
- }
- }
- noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_capture,&aliasData);
- if(noError)
- {
- if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED)))
- {
- PA_DEBUG(("Device %d has capture alias\n",device));
- aliasFlags |= Alias_kCapture; /* Has capture alias */
- }
- else
- {
- PA_DEBUG(("Device %d has no capture alias\n",device));
- }
- }
- if(!aliasFlags)
- invalidDevices++; /* This was not a valid capture or render audio device */
- }
- /* Remember how many there are */
- filterCount = device-invalidDevices;
- PA_DEBUG(("Interfaces found: %d\n",device-invalidDevices));
- /* Now allocate the list of pointers to devices */
- ppFilters = (PaWinWdmFilter**)PaUtil_AllocateMemory( sizeof(PaWinWdmFilter*) * filterCount);
- if( ppFilters == 0 )
- {
- if(handle != NULL)
- SetupDiDestroyDeviceInfoList(handle);
- *pResult = paInsufficientMemory;
- return NULL;
- }
- /* Now create filter objects for each interface found */
- slot = 0;
- for( device = 0;;device++ )
- {
- interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
- interfaceData.Reserved = 0;
- aliasData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
- aliasData.Reserved = 0;
- devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
- devInfoData.Reserved = 0;
- streamingType = Type_kWaveCyclic;
- noError = SetupDiEnumDeviceInterfaces(handle,NULL,category,device,&interfaceData);
- if( !noError )
- break; /* No more devices */
- /* Check this one has the render or capture alias */
- aliasFlags = 0;
- noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_render,&aliasData);
- if(noError)
- {
- if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED)))
- {
- PA_DEBUG(("Device %d has render alias\n",device));
- aliasFlags |= Alias_kRender; /* Has render alias */
- }
- }
- noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_capture,&aliasData);
- if(noError)
- {
- if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED)))
- {
- PA_DEBUG(("Device %d has capture alias\n",device));
- aliasFlags |= Alias_kCapture; /* Has capture alias */
- }
- }
- if(!aliasFlags)
- {
- continue; /* This was not a valid capture or render audio device */
- }
- else
- {
- /* Check if filter is WaveRT, if not it is a WaveCyclic */
- noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,category_realtime,&aliasData);
- if (noError)
- {
- PA_DEBUG(("Device %d has realtime alias\n",device));
- aliasFlags |= Alias_kRealtime;
- streamingType = Type_kWaveRT;
- }
- }
- noError = SetupDiGetDeviceInterfaceDetailW(handle,&interfaceData,devInterfaceDetails,sizeInterface,NULL,&devInfoData);
- if( noError )
- {
- DWORD type;
- WCHAR friendlyName[MAX_PATH] = {0};
- DWORD sizeFriendlyName;
- PaWinWdmFilter* newFilter = 0;
- PaError result = paNoError;
- /* Try to get the "friendly name" for this interface */
- sizeFriendlyName = sizeof(friendlyName);
- if (IsEarlierThanVista() && IsUSBDevice(devInterfaceDetails->DevicePath))
- {
- /* XP and USB audio device needs to look elsewhere, otherwise it'll only be a "USB Audio Device". Not
- very literate. */
- if (!SetupDiGetDeviceRegistryPropertyW(handle,
- &devInfoData,
- SPDRP_LOCATION_INFORMATION,
- &type,
- (BYTE*)friendlyName,
- sizeof(friendlyName),
- NULL))
- {
- friendlyName[0] = 0;
- }
- }
- if (friendlyName[0] == 0 || IsNameUSBAudioDevice(friendlyName))
- {
- /* Fix contributed by Ben Allison
- * Removed KEY_SET_VALUE from flags on following call
- * as its causes failure when running without admin rights
- * and it was not required */
- HKEY hkey=SetupDiOpenDeviceInterfaceRegKey(handle,&interfaceData,0,KEY_QUERY_VALUE);
- if(hkey!=INVALID_HANDLE_VALUE)
- {
- noError = RegQueryValueExW(hkey,L"FriendlyName",0,&type,(BYTE*)friendlyName,&sizeFriendlyName);
- if( noError == ERROR_SUCCESS )
- {
- PA_DEBUG(("Interface %d, Name: %s\n",device,friendlyName));
- RegCloseKey(hkey);
- }
- else
- {
- friendlyName[0] = 0;
- }
- }
- }
- TrimString(friendlyName, sizeFriendlyName);
- newFilter = FilterNew(streamingType,
- devInfoData.DevInst,
- devInterfaceDetails->DevicePath,
- friendlyName,
- &result);
- if( result == paNoError )
- {
- int pin;
- unsigned filterIOs = 0;
- /* Increment number of "devices" */
- for (pin = 0; pin < newFilter->pinCount; ++pin)
- {
- PaWinWdmPin* pPin = newFilter->pins[pin];
- if (pPin == NULL)
- continue;
- filterIOs += max(1, pPin->inputCount);
- }
- noOfPaDevices += filterIOs;
- PA_DEBUG(("Filter (%s) created with %d valid pins (total I/Os: %u)\n", ((newFilter->devInfo.streamingType==Type_kWaveRT)?"WaveRT":"WaveCyclic"), newFilter->validPinCount, filterIOs));
- assert(slot < filterCount);
- ppFilters[slot] = newFilter;
- slot++;
- }
- else
- {
- PA_DEBUG(("Filter NOT created\n"));
- /* As there are now less filters than we initially thought
- * we must reduce the count by one */
- filterCount--;
- }
- }
- }
- /* Clean up */
- if(handle != NULL)
- SetupDiDestroyDeviceInfoList(handle);
- *pFilterCount = filterCount;
- *pNoOfPaDevices = noOfPaDevices;
- return ppFilters;
- }
- typedef struct PaNameHashIndex
- {
- unsigned index;
- unsigned count;
- ULONG hash;
- struct PaNameHashIndex *next;
- } PaNameHashIndex;
- typedef struct PaNameHashObject
- {
- PaNameHashIndex* list;
- PaUtilAllocationGroup* allocGroup;
- } PaNameHashObject;
- static ULONG GetNameHash(const wchar_t* str, const BOOL input)
- {
- /* This is to make sure that a name that exists as both input & output won't get the same hash value */
- const ULONG fnv_prime = (input ? 0x811C9DD7 : 0x811FEB0B);
- ULONG hash = 0;
- for(; *str != 0; str++)
- {
- hash *= fnv_prime;
- hash ^= (*str);
- }
- assert(hash != 0);
- return hash;
- }
- static PaError CreateHashEntry(PaNameHashObject* obj, const wchar_t* name, const BOOL input)
- {
- ULONG hash = GetNameHash(name, input);
- PaNameHashIndex * pLast = NULL;
- PaNameHashIndex * p = obj->list;
- while (p != 0)
- {
- if (p->hash == hash)
- {
- break;
- }
- pLast = p;
- p = p->next;
- }
- if (p == NULL)
- {
- p = (PaNameHashIndex*)PaUtil_GroupAllocateMemory(obj->allocGroup, sizeof(PaNameHashIndex));
- if (p == NULL)
- {
- return paInsufficientMemory;
- }
- p->hash = hash;
- p->count = 1;
- if (pLast != 0)
- {
- assert(pLast->next == 0);
- pLast->next = p;
- }
- if (obj->list == 0)
- {
- obj->list = p;
- }
- }
- else
- {
- ++p->count;
- }
- return paNoError;
- }
- static PaError InitNameHashObject(PaNameHashObject* obj, PaWinWdmFilter* pFilter)
- {
- int i;
- obj->allocGroup = PaUtil_CreateAllocationGroup();
- if (obj->allocGroup == NULL)
- {
- return paInsufficientMemory;
- }
- for (i = 0; i < pFilter->pinCount; ++i)
- {
- unsigned m;
- PaWinWdmPin* pin = pFilter->pins[i];
- if (pin == NULL)
- continue;
- for (m = 0; m < max(1, pin->inputCount); ++m)
- {
- const BOOL isInput = (pin->dataFlow == KSPIN_DATAFLOW_OUT);
- const wchar_t* name = (pin->inputs == NULL) ? pin->friendlyName : pin->inputs[m]->friendlyName;
- PaError result = CreateHashEntry(obj, name, isInput);
- if (result != paNoError)
- {
- return result;
- }
- }
- }
- return paNoError;
- }
- static void DeinitNameHashObject(PaNameHashObject* obj)
- {
- assert(obj != 0);
- PaUtil_FreeAllAllocations(obj->allocGroup);
- PaUtil_DestroyAllocationGroup(obj->allocGroup);
- memset(obj, 0, sizeof(PaNameHashObject));
- }
- static unsigned GetNameIndex(PaNameHashObject* obj, const wchar_t* name, const BOOL input)
- {
- ULONG hash = GetNameHash(name, input);
- PaNameHashIndex* p = obj->list;
- while (p != NULL)
- {
- if (p->hash == hash)
- {
- if (p->count > 1)
- {
- return (++p->index);
- }
- else
- {
- return 0;
- }
- }
- p = p->next;
- }
- // Should never get here!!
- assert(FALSE);
- return 0;
- }
- static PaError ScanDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex hostApiIndex, void **scanResults, int *newDeviceCount )
- {
- PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
- PaError result = paNoError;
- PaWinWdmFilter** ppFilters = 0;
- PaWinWDMScanDeviceInfosResults *outArgument = 0;
- int filterCount = 0;
- int totalDeviceCount = 0;
- int idxDevice = 0;
- ppFilters = BuildFilterList( &filterCount, &totalDeviceCount, &result );
- if( result != paNoError )
- {
- goto error;
- }
- if( totalDeviceCount > 0 )
- {
- PaWinWdmDeviceInfo *deviceInfoArray = 0;
- int idxFilter;
- int i;
- /* Allocate the out param for all the info we need */
- outArgument = (PaWinWDMScanDeviceInfosResults *) PaUtil_GroupAllocateMemory(
- wdmHostApi->allocations, sizeof(PaWinWDMScanDeviceInfosResults) );
- if( !outArgument )
- {
- result = paInsufficientMemory;
- goto error;
- }
- outArgument->defaultInputDevice = paNoDevice;
- outArgument->defaultOutputDevice = paNoDevice;
- outArgument->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
- wdmHostApi->allocations, sizeof(PaDeviceInfo*) * totalDeviceCount );
- if( !outArgument->deviceInfos )
- {
- result = paInsufficientMemory;
- goto error;
- }
- /* allocate all device info structs in a contiguous block */
- deviceInfoArray = (PaWinWdmDeviceInfo*)PaUtil_GroupAllocateMemory(
- wdmHostApi->allocations, sizeof(PaWinWdmDeviceInfo) * totalDeviceCount );
- if( !deviceInfoArray )
- {
- result = paInsufficientMemory;
- goto error;
- }
- /* Make sure all items in array */
- for( i = 0 ; i < totalDeviceCount; ++i )
- {
- PaDeviceInfo *deviceInfo = &deviceInfoArray[i].inheritedDeviceInfo;
- deviceInfo->structVersion = 2;
- deviceInfo->hostApi = hostApiIndex;
- deviceInfo->name = 0;
- outArgument->deviceInfos[ i ] = deviceInfo;
- }
- idxDevice = 0;
- for (idxFilter = 0; idxFilter < filterCount; ++idxFilter)
- {
- PaNameHashObject nameHash = {0};
- PaWinWdmFilter* pFilter = ppFilters[idxFilter];
- if( pFilter == NULL )
- continue;
- if (InitNameHashObject(&nameHash, pFilter) != paNoError)
- {
- DeinitNameHashObject(&nameHash);
- continue;
- }
- for (i = 0; i < pFilter->pinCount; ++i)
- {
- unsigned m;
- ULONG nameIndex = 0;
- ULONG nameIndexHash = 0;
- PaWinWdmPin* pin = pFilter->pins[i];
- if (pin == NULL)
- continue;
- for (m = 0; m < max(1, pin->inputCount); ++m)
- {
- PaWinWdmDeviceInfo *wdmDeviceInfo = (PaWinWdmDeviceInfo *)outArgument->deviceInfos[idxDevice];
- PaDeviceInfo *deviceInfo = &wdmDeviceInfo->inheritedDeviceInfo;
- wchar_t localCompositeName[MAX_PATH];
- unsigned nameIndex = 0;
- const BOOL isInput = (pin->dataFlow == KSPIN_DATAFLOW_OUT);
- wdmDeviceInfo->filter = pFilter;
- deviceInfo->structVersion = 2;
- deviceInfo->hostApi = hostApiIndex;
- deviceInfo->name = wdmDeviceInfo->compositeName;
- /* deviceInfo->hostApiSpecificDeviceInfo = &pFilter->devInfo; */
- wdmDeviceInfo->pin = pin->pinId;
- /* Get the name of the "device" */
- if (pin->inputs == NULL)
- {
- wcsncpy(localCompositeName, pin->friendlyName, MAX_PATH);
- wdmDeviceInfo->muxPosition = -1;
- wdmDeviceInfo->endpointPinId = pin->endpointPinId;
- }
- else
- {
- PaWinWdmMuxedInput* input = pin->inputs[m];
- wcsncpy(localCompositeName, input->friendlyName, MAX_PATH);
- wdmDeviceInfo->muxPosition = (int)m;
- wdmDeviceInfo->endpointPinId = input->endpointPinId;
- }
- {
- /* Get base length */
- size_t n = wcslen(localCompositeName);
- /* Check if there are more entries with same name (which might very well be the case), if there
- are, the name will be postfixed with an index. */
- nameIndex = GetNameIndex(&nameHash, localCompositeName, isInput);
- if (nameIndex > 0)
- {
- /* This name has multiple instances, so we post fix with a number */
- n += _snwprintf(localCompositeName + n, MAX_PATH - n, L" %u", nameIndex);
- }
- /* Postfix with filter name */
- _snwprintf(localCompositeName + n, MAX_PATH - n, L" (%s)", pFilter->friendlyName);
- }
- /* Convert wide char string to utf-8 */
- WideCharToMultiByte(CP_UTF8, 0, localCompositeName, -1, wdmDeviceInfo->compositeName, MAX_PATH, NULL, NULL);
- /* NB! WDM/KS has no concept of a full-duplex device, each pin is either an input or and output */
- if (isInput)
- {
- /* INPUT ! */
- deviceInfo->maxInputChannels = pin->maxChannels;
- deviceInfo->maxOutputChannels = 0;
- if (outArgument->defaultInputDevice == paNoDevice)
- {
- outArgument->defaultInputDevice = idxDevice;
- }
- }
- else
- {
- /* OUTPUT ! */
- deviceInfo->maxInputChannels = 0;
- deviceInfo->maxOutputChannels = pin->maxChannels;
- if (outArgument->defaultOutputDevice == paNoDevice)
- {
- outArgument->defaultOutputDevice = idxDevice;
- }
- }
- /* These low values are not very useful because
- * a) The lowest latency we end up with can depend on many factors such
- * as the device buffer sizes/granularities, sample rate, channels and format
- * b) We cannot know the device buffer sizes until we try to open/use it at
- * a particular setting
- * So: we give 512x48000Hz frames as the default low input latency
- **/
- switch (pFilter->devInfo.streamingType)
- {
- case Type_kWaveCyclic:
- if (IsEarlierThanVista())
- {
- /* XP doesn't tolerate low latency, unless the Process Priority Class is set to REALTIME_PRIORITY_CLASS
- through SetPriorityClass, then 10 ms is quite feasible. However, one should then bear in mind that ALL of
- the process is running in REALTIME_PRIORITY_CLASS, which might not be appropriate for an application with
- a GUI . In this case it is advisable to separate the audio engine in another process and use IPC to communicate
- with it. */
- deviceInfo->defaultLowInputLatency = 0.02;
- deviceInfo->defaultLowOutputLatency = 0.02;
- }
- else
- {
- /* This is a conservative estimate. Most WaveCyclic drivers will limit the available latency, but f.i. my Edirol
- PCR-A30 can reach 3 ms latency easily... */
- deviceInfo->defaultLowInputLatency = 0.01;
- deviceInfo->defaultLowOutputLatency = 0.01;
- }
- deviceInfo->defaultHighInputLatency = (4096.0/48000.0);
- deviceInfo->defaultHighOutputLatency = (4096.0/48000.0);
- deviceInfo->defaultSampleRate = (double)(pin->defaultSampleRate);
- break;
- case Type_kWaveRT:
- /* This is also a conservative estimate, based on WaveRT polled mode. In polled mode, the latency will be dictated
- by the buffer size given by the driver. */
- deviceInfo->defaultLowInputLatency = 0.01;
- deviceInfo->defaultLowOutputLatency = 0.01;
- deviceInfo->defaultHighInputLatency = 0.04;
- deviceInfo->defaultHighOutputLatency = 0.04;
- deviceInfo->defaultSampleRate = (double)(pin->defaultSampleRate);
- break;
- default:
- assert(0);
- break;
- }
- /* Add reference to filter */
- FilterAddRef(wdmDeviceInfo->filter);
- assert(idxDevice < totalDeviceCount);
- ++idxDevice;
- }
- }
- /* If no one has add ref'd the filter, drop it */
- if (pFilter->filterRefCount == 0)
- {
- FilterFree(pFilter);
- }
- /* Deinitialize name hash object */
- DeinitNameHashObject(&nameHash);
- }
- }
- *scanResults = outArgument;
- *newDeviceCount = idxDevice;
- return result;
- error:
- result = DisposeDeviceInfos(hostApi, outArgument, totalDeviceCount);
- return result;
- }
- static PaError CommitDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, void *scanResults, int deviceCount )
- {
- PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
- hostApi->info.deviceCount = 0;
- hostApi->info.defaultInputDevice = paNoDevice;
- hostApi->info.defaultOutputDevice = paNoDevice;
- /* Free any old memory which might be in the device info */
- if( hostApi->deviceInfos )
- {
- PaWinWDMScanDeviceInfosResults* localScanResults = (PaWinWDMScanDeviceInfosResults*)PaUtil_GroupAllocateMemory(
- wdmHostApi->allocations, sizeof(PaWinWDMScanDeviceInfosResults));
- localScanResults->deviceInfos = hostApi->deviceInfos;
- DisposeDeviceInfos(hostApi, &localScanResults, hostApi->info.deviceCount);
- hostApi->deviceInfos = NULL;
- }
- if( scanResults != NULL )
- {
- PaWinWDMScanDeviceInfosResults *scanDeviceInfosResults = ( PaWinWDMScanDeviceInfosResults * ) scanResults;
- if( deviceCount > 0 )
- {
- /* use the array allocated in ScanDeviceInfos() as our deviceInfos */
- hostApi->deviceInfos = scanDeviceInfosResults->deviceInfos;
- hostApi->info.defaultInputDevice = scanDeviceInfosResults->defaultInputDevice;
- hostApi->info.defaultOutputDevice = scanDeviceInfosResults->defaultOutputDevice;
- hostApi->info.deviceCount = deviceCount;
- }
- PaUtil_GroupFreeMemory( wdmHostApi->allocations, scanDeviceInfosResults );
- }
- return paNoError;
- }
- static PaError DisposeDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, void *scanResults, int deviceCount )
- {
- PaWinWdmHostApiRepresentation *winDsHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
- if( scanResults != NULL )
- {
- PaWinWDMScanDeviceInfosResults *scanDeviceInfosResults = ( PaWinWDMScanDeviceInfosResults * ) scanResults;
- if( scanDeviceInfosResults->deviceInfos )
- {
- int i;
- for (i = 0; i < deviceCount; ++i)
- {
- PaWinWdmDeviceInfo* pDevice = (PaWinWdmDeviceInfo*)scanDeviceInfosResults->deviceInfos[i];
- if (pDevice->filter != 0)
- {
- FilterFree(pDevice->filter);
- }
- }
- PaUtil_GroupFreeMemory( winDsHostApi->allocations, scanDeviceInfosResults->deviceInfos[0] ); /* all device info structs are allocated in a block so we can destroy them here */
- PaUtil_GroupFreeMemory( winDsHostApi->allocations, scanDeviceInfosResults->deviceInfos );
- }
- PaUtil_GroupFreeMemory( winDsHostApi->allocations, scanDeviceInfosResults );
- }
- return paNoError;
- }
- PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
- {
- PaError result = paNoError;
- int deviceCount = 0;
- void *scanResults = 0;
- PaWinWdmHostApiRepresentation *wdmHostApi = NULL;
- PA_LOGE_;
- #ifdef PA_WDMKS_SET_TREF
- tRef = PaUtil_GetTime();
- #endif
- /*
- Attempt to load the KSUSER.DLL without which we cannot create pins
- We will unload this on termination
- */
- if(DllKsUser == NULL)
- {
- DllKsUser = LoadLibrary(TEXT("ksuser.dll"));
- if(DllKsUser == NULL)
- goto error;
- }
- FunctionKsCreatePin = (KSCREATEPIN*)GetProcAddress(DllKsUser, "KsCreatePin");
- if(FunctionKsCreatePin == NULL)
- goto error;
- /* Attempt to load AVRT.DLL, if we can't, then we'll just use time critical prio instead... */
- if(paWinWDMKSAvRtEntryPoints.hInstance == NULL)
- {
- paWinWDMKSAvRtEntryPoints.hInstance = LoadLibrary(TEXT("avrt.dll"));
- if (paWinWDMKSAvRtEntryPoints.hInstance != NULL)
- {
- paWinWDMKSAvRtEntryPoints.AvSetMmThreadCharacteristics =
- (HANDLE(WINAPI*)(LPCSTR,LPDWORD))GetProcAddress(paWinWDMKSAvRtEntryPoints.hInstance,"AvSetMmThreadCharacteristicsA");
- paWinWDMKSAvRtEntryPoints.AvRevertMmThreadCharacteristics =
- (BOOL(WINAPI*)(HANDLE))GetProcAddress(paWinWDMKSAvRtEntryPoints.hInstance, "AvRevertMmThreadCharacteristics");
- paWinWDMKSAvRtEntryPoints.AvSetMmThreadPriority =
- (BOOL(WINAPI*)(HANDLE,PA_AVRT_PRIORITY))GetProcAddress(paWinWDMKSAvRtEntryPoints.hInstance, "AvSetMmThreadPriority");
- }
- }
- wdmHostApi = (PaWinWdmHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinWdmHostApiRepresentation) );
- if( !wdmHostApi )
- {
- result = paInsufficientMemory;
- goto error;
- }
- wdmHostApi->allocations = PaUtil_CreateAllocationGroup();
- if( !wdmHostApi->allocations )
- {
- result = paInsufficientMemory;
- goto error;
- }
- *hostApi = &wdmHostApi->inheritedHostApiRep;
- (*hostApi)->info.structVersion = 1;
- (*hostApi)->info.type = paWDMKS;
- (*hostApi)->info.name = "Windows WDM-KS";
- /* these are all updated by CommitDeviceInfos() */
- (*hostApi)->info.deviceCount = 0;
- (*hostApi)->info.defaultInputDevice = paNoDevice;
- (*hostApi)->info.defaultOutputDevice = paNoDevice;
- (*hostApi)->deviceInfos = 0;
- result = ScanDeviceInfos(&wdmHostApi->inheritedHostApiRep, hostApiIndex, &scanResults, &deviceCount);
- if (result != paNoError)
- {
- goto error;
- }
- CommitDeviceInfos(&wdmHostApi->inheritedHostApiRep, hostApiIndex, scanResults, deviceCount);
- (*hostApi)->Terminate = Terminate;
- (*hostApi)->OpenStream = OpenStream;
- (*hostApi)->IsFormatSupported = IsFormatSupported;
- /* In preparation for hotplug
- (*hostApi)->ScanDeviceInfos = ScanDeviceInfos;
- (*hostApi)->CommitDeviceInfos = CommitDeviceInfos;
- (*hostApi)->DisposeDeviceInfos = DisposeDeviceInfos;
- */
- PaUtil_InitializeStreamInterface( &wdmHostApi->callbackStreamInterface, CloseStream, StartStream,
- StopStream, AbortStream, IsStreamStopped, IsStreamActive,
- GetStreamTime, GetStreamCpuLoad,
- PaUtil_DummyRead, PaUtil_DummyWrite,
- PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
- PaUtil_InitializeStreamInterface( &wdmHostApi->blockingStreamInterface, CloseStream, StartStream,
- StopStream, AbortStream, IsStreamStopped, IsStreamActive,
- GetStreamTime, PaUtil_DummyGetCpuLoad,
- ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
- PA_LOGL_;
- return result;
- error:
- Terminate( (PaUtilHostApiRepresentation*)wdmHostApi );
- PA_LOGL_;
- return result;
- }
- static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
- {
- PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
- PA_LOGE_;
- /* Do not unload the libraries */
- if( DllKsUser != NULL )
- {
- FreeLibrary( DllKsUser );
- DllKsUser = NULL;
- }
- if( paWinWDMKSAvRtEntryPoints.hInstance != NULL )
- {
- FreeLibrary( paWinWDMKSAvRtEntryPoints.hInstance );
- paWinWDMKSAvRtEntryPoints.hInstance = NULL;
- }
- if( wdmHostApi)
- {
- PaWinWDMScanDeviceInfosResults* localScanResults = (PaWinWDMScanDeviceInfosResults*)PaUtil_GroupAllocateMemory(
- wdmHostApi->allocations, sizeof(PaWinWDMScanDeviceInfosResults));
- localScanResults->deviceInfos = hostApi->deviceInfos;
- DisposeDeviceInfos(hostApi, localScanResults, hostApi->info.deviceCount);
- if( wdmHostApi->allocations )
- {
- PaUtil_FreeAllAllocations( wdmHostApi->allocations );
- PaUtil_DestroyAllocationGroup( wdmHostApi->allocations );
- }
- PaUtil_FreeMemory( wdmHostApi );
- }
- PA_LOGL_;
- }
- static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate )
- {
- int inputChannelCount, outputChannelCount;
- PaSampleFormat inputSampleFormat, outputSampleFormat;
- PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
- PaWinWdmFilter* pFilter;
- int result = paFormatIsSupported;
- WAVEFORMATEXTENSIBLE wfx;
- PaWinWaveFormatChannelMask channelMask;
- PA_LOGE_;
- if( inputParameters )
- {
- PaWinWdmDeviceInfo* pDeviceInfo = (PaWinWdmDeviceInfo*)wdmHostApi->inheritedHostApiRep.deviceInfos[inputParameters->device];
- PaWinWdmPin* pin;
- unsigned fmt;
- unsigned long testFormat = 0;
- unsigned validBits = 0;
- inputChannelCount = inputParameters->channelCount;
- inputSampleFormat = inputParameters->sampleFormat;
- /* all standard sample formats are supported by the buffer adapter,
- this implementation doesn't support any custom sample formats */
- if( inputSampleFormat & paCustomFormat )
- {
- PaWinWDM_SetLastErrorInfo(paSampleFormatNotSupported, "IsFormatSupported: Custom input format not supported");
- return paSampleFormatNotSupported;
- }
- /* unless alternate device specification is supported, reject the use of
- paUseHostApiSpecificDeviceSpecification */
- if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
- {
- PaWinWDM_SetLastErrorInfo(paInvalidDevice, "IsFormatSupported: paUseHostApiSpecificDeviceSpecification not supported");
- return paInvalidDevice;
- }
- /* check that input device can support inputChannelCount */
- if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
- {
- PaWinWDM_SetLastErrorInfo(paInvalidChannelCount, "IsFormatSupported: Invalid input channel count");
- return paInvalidChannelCount;
- }
- /* validate inputStreamInfo */
- if( inputParameters->hostApiSpecificStreamInfo )
- {
- PaWinWDM_SetLastErrorInfo(paIncompatibleHostApiSpecificStreamInfo, "Host API stream info not supported");
- return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
- }
- pFilter = pDeviceInfo->filter;
- pin = pFilter->pins[pDeviceInfo->pin];
- /* Find out the testing format */
- for (fmt = paFloat32; fmt <= paUInt8; fmt <<= 1)
- {
- if ((fmt & pin->formats) != 0)
- {
- /* Found a matching format! */
- testFormat = fmt;
- break;
- }
- }
- if (testFormat == 0)
- {
- PaWinWDM_SetLastErrorInfo(result, "IsFormatSupported(capture) failed: no testformat found!");
- return paUnanticipatedHostError;
- }
- /* Due to special considerations, WaveRT devices with paInt24 should be tested with paInt32 and
- valid bits = 24 (instead of 24 bit samples) */
- if (pFilter->devInfo.streamingType == Type_kWaveRT && testFormat == paInt24)
- {
- PA_DEBUG(("IsFormatSupported (capture): WaveRT overriding testFormat paInt24 with paInt32 (24 valid bits)"));
- testFormat = paInt32;
- validBits = 24;
- }
- /* Check that the input format is supported */
- channelMask = PaWin_DefaultChannelMask(inputChannelCount);
- PaWin_InitializeWaveFormatExtensible((PaWinWaveFormat*)&wfx,
- inputChannelCount,
- testFormat,
- PaWin_SampleFormatToLinearWaveFormatTag(testFormat),
- sampleRate,
- channelMask );
- if (validBits != 0)
- {
- wfx.Samples.wValidBitsPerSample = validBits;
- }
- result = PinIsFormatSupported(pin, (const WAVEFORMATEX*)&wfx);
- if( result != paNoError )
- {
- /* Try a WAVE_FORMAT_PCM instead */
- PaWin_InitializeWaveFormatEx((PaWinWaveFormat*)&wfx,
- inputChannelCount,
- testFormat,
- PaWin_SampleFormatToLinearWaveFormatTag(testFormat),
- sampleRate);
- if (validBits != 0)
- {
- wfx.Samples.wValidBitsPerSample = validBits;
- }
- result = PinIsFormatSupported(pin, (const WAVEFORMATEX*)&wfx);
- if( result != paNoError )
- {
- PaWinWDM_SetLastErrorInfo(result, "IsFormatSupported(capture) failed: sr=%u,ch=%u,bits=%u", wfx.Format.nSamplesPerSec, wfx.Format.nChannels, wfx.Format.wBitsPerSample);
- return result;
- }
- }
- }
- else
- {
- inputChannelCount = 0;
- }
- if( outputParameters )
- {
- PaWinWdmDeviceInfo* pDeviceInfo = (PaWinWdmDeviceInfo*)wdmHostApi->inheritedHostApiRep.deviceInfos[outputParameters->device];
- PaWinWdmPin* pin;
- unsigned fmt;
- unsigned long testFormat = 0;
- unsigned validBits = 0;
- outputChannelCount = outputParameters->channelCount;
- outputSampleFormat = outputParameters->sampleFormat;
- /* all standard sample formats are supported by the buffer adapter,
- this implementation doesn't support any custom sample formats */
- if( outputSampleFormat & paCustomFormat )
- {
- PaWinWDM_SetLastErrorInfo(paSampleFormatNotSupported, "IsFormatSupported: Custom output format not supported");
- return paSampleFormatNotSupported;
- }
- /* unless alternate device specification is supported, reject the use of
- paUseHostApiSpecificDeviceSpecification */
- if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
- {
- PaWinWDM_SetLastErrorInfo(paInvalidDevice, "IsFormatSupported: paUseHostApiSpecificDeviceSpecification not supported");
- return paInvalidDevice;
- }
- /* check that output device can support outputChannelCount */
- if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
- {
- PaWinWDM_SetLastErrorInfo(paInvalidChannelCount, "Invalid output channel count");
- return paInvalidChannelCount;
- }
- /* validate outputStreamInfo */
- if( outputParameters->hostApiSpecificStreamInfo )
- {
- PaWinWDM_SetLastErrorInfo(paIncompatibleHostApiSpecificStreamInfo, "Host API stream info not supported");
- return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
- }
- pFilter = pDeviceInfo->filter;
- pin = pFilter->pins[pDeviceInfo->pin];
- /* Find out the testing format */
- for (fmt = paFloat32; fmt <= paUInt8; fmt <<= 1)
- {
- if ((fmt & pin->formats) != 0)
- {
- /* Found a matching format! */
- testFormat = fmt;
- break;
- }
- }
- if (testFormat == 0)
- {
- PaWinWDM_SetLastErrorInfo(result, "IsFormatSupported(render) failed: no testformat found!");
- return paUnanticipatedHostError;
- }
- /* Due to special considerations, WaveRT devices with paInt24 should be tested with paInt32 and
- valid bits = 24 (instead of 24 bit samples) */
- if (pFilter->devInfo.streamingType == Type_kWaveRT && testFormat == paInt24)
- {
- PA_DEBUG(("IsFormatSupported (render): WaveRT overriding testFormat paInt24 with paInt32 (24 valid bits)"));
- testFormat = paInt32;
- validBits = 24;
- }
- /* Check that the output format is supported */
- channelMask = PaWin_DefaultChannelMask(outputChannelCount);
- PaWin_InitializeWaveFormatExtensible((PaWinWaveFormat*)&wfx,
- outputChannelCount,
- testFormat,
- PaWin_SampleFormatToLinearWaveFormatTag(testFormat),
- sampleRate,
- channelMask );
- if (validBits != 0)
- {
- wfx.Samples.wValidBitsPerSample = validBits;
- }
- result = PinIsFormatSupported(pin, (const WAVEFORMATEX*)&wfx);
- if( result != paNoError )
- {
- /* Try a WAVE_FORMAT_PCM instead */
- PaWin_InitializeWaveFormatEx((PaWinWaveFormat*)&wfx,
- outputChannelCount,
- testFormat,
- PaWin_SampleFormatToLinearWaveFormatTag(testFormat),
- sampleRate);
- if (validBits != 0)
- {
- wfx.Samples.wValidBitsPerSample = validBits;
- }
- result = PinIsFormatSupported(pin, (const WAVEFORMATEX*)&wfx);
- if( result != paNoError )
- {
- PaWinWDM_SetLastErrorInfo(result, "IsFormatSupported(render) failed: %u,%u,%u", wfx.Format.nSamplesPerSec, wfx.Format.nChannels, wfx.Format.wBitsPerSample);
- return result;
- }
- }
- }
- else
- {
- outputChannelCount = 0;
- }
- /*
- IMPLEMENT ME:
- - if a full duplex stream is requested, check that the combination
- of input and output parameters is supported if necessary
- - check that the device supports sampleRate
- Because the buffer adapter handles conversion between all standard
- sample formats, the following checks are only required if paCustomFormat
- is implemented, or under some other unusual conditions.
- - check that input device can support inputSampleFormat, or that
- we have the capability to convert from inputSampleFormat to
- a native format
- - check that output device can support outputSampleFormat, or that
- we have the capability to convert from outputSampleFormat to
- a native format
- */
- if((inputChannelCount == 0)&&(outputChannelCount == 0))
- {
- PaWinWDM_SetLastErrorInfo(paSampleFormatNotSupported, "No input or output channels defined");
- result = paSampleFormatNotSupported; /* Not right error */
- }
- PA_LOGL_;
- return result;
- }
- static void ResetStreamEvents(PaWinWdmStream* stream)
- {
- unsigned i;
- ResetEvent(stream->eventAbort);
- ResetEvent(stream->eventStreamStart[StreamStart_kOk]);
- ResetEvent(stream->eventStreamStart[StreamStart_kFailed]);
- for (i=0; i<stream->capture.noOfPackets; ++i)
- {
- if (stream->capture.events && stream->capture.events[i])
- {
- ResetEvent(stream->capture.events[i]);
- }
- }
- for (i=0; i<stream->render.noOfPackets; ++i)
- {
- if (stream->render.events && stream->render.events[i])
- {
- ResetEvent(stream->render.events[i]);
- }
- }
- }
- static void CloseStreamEvents(PaWinWdmStream* stream)
- {
- unsigned i;
- PaWinWdmIOInfo* ios[2] = { &stream->capture, &stream->render };
- if (stream->eventAbort)
- {
- CloseHandle(stream->eventAbort);
- stream->eventAbort = 0;
- }
- if (stream->eventStreamStart[StreamStart_kOk])
- {
- CloseHandle(stream->eventStreamStart[StreamStart_kOk]);
- }
- if (stream->eventStreamStart[StreamStart_kFailed])
- {
- CloseHandle(stream->eventStreamStart[StreamStart_kFailed]);
- }
- for (i = 0; i < 2; ++i)
- {
- unsigned j;
- /* Unregister notification handles for WaveRT */
- if (ios[i]->pPin && ios[i]->pPin->parentFilter->devInfo.streamingType == Type_kWaveRT &&
- ios[i]->pPin->pinKsSubType == SubType_kNotification &&
- ios[i]->events != 0)
- {
- PinUnregisterNotificationHandle(ios[i]->pPin, ios[i]->events[0]);
- }
- for (j=0; j < ios[i]->noOfPackets; ++j)
- {
- if (ios[i]->events && ios[i]->events[j])
- {
- CloseHandle(ios[i]->events[j]);
- ios[i]->events[j] = 0;
- }
- }
- }
- }
- static unsigned NextPowerOf2(unsigned val)
- {
- val--;
- val = (val >> 1) | val;
- val = (val >> 2) | val;
- val = (val >> 4) | val;
- val = (val >> 8) | val;
- val = (val >> 16) | val;
- return ++val;
- }
- static PaError ValidateSpecificStreamParameters(
- const PaStreamParameters *streamParameters,
- const PaWinWDMKSInfo *streamInfo)
- {
- if( streamInfo )
- {
- if( streamInfo->size != sizeof( PaWinWDMKSInfo )
- || streamInfo->version != 1 )
- {
- PA_DEBUG(("Stream parameters: size or version not correct"));
- return paIncompatibleHostApiSpecificStreamInfo;
- }
- if (streamInfo->noOfPackets != 0 &&
- (streamInfo->noOfPackets < 2 || streamInfo->noOfPackets > 8))
- {
- PA_DEBUG(("Stream parameters: noOfPackets %u out of range [2,8]", streamInfo->noOfPackets));
- return paIncompatibleHostApiSpecificStreamInfo;
- }
- }
- return paNoError;
- }
- /* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
- static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
- PaStream** s,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate,
- unsigned long framesPerUserBuffer,
- PaStreamFlags streamFlags,
- PaStreamCallback *streamCallback,
- void *userData )
- {
- PaError result = paNoError;
- PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
- PaWinWdmStream *stream = 0;
- /* unsigned long framesPerHostBuffer; these may not be equivalent for all implementations */
- PaSampleFormat inputSampleFormat, outputSampleFormat;
- PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
- int userInputChannels,userOutputChannels;
- WAVEFORMATEXTENSIBLE wfx;
- PA_LOGE_;
- PA_DEBUG(("OpenStream:sampleRate = %f\n",sampleRate));
- PA_DEBUG(("OpenStream:framesPerBuffer = %lu\n",framesPerUserBuffer));
- if( inputParameters )
- {
- userInputChannels = inputParameters->channelCount;
- inputSampleFormat = inputParameters->sampleFormat;
- /* unless alternate device specification is supported, reject the use of
- paUseHostApiSpecificDeviceSpecification */
- if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
- {
- PaWinWDM_SetLastErrorInfo(paInvalidDevice, "paUseHostApiSpecificDeviceSpecification(in) not supported");
- return paInvalidDevice;
- }
- /* check that input device can support stream->userInputChannels */
- if( userInputChannels > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
- {
- PaWinWDM_SetLastErrorInfo(paInvalidChannelCount, "Invalid input channel count");
- return paInvalidChannelCount;
- }
- /* validate inputStreamInfo */
- result = ValidateSpecificStreamParameters(inputParameters, inputParameters->hostApiSpecificStreamInfo);
- if(result != paNoError)
- {
- PaWinWDM_SetLastErrorInfo(result, "Host API stream info not supported (in)");
- return result; /* this implementation doesn't use custom stream info */
- }
- }
- else
- {
- userInputChannels = 0;
- inputSampleFormat = hostInputSampleFormat = paInt16; /* Supress 'uninitialised var' warnings. */
- }
- if( outputParameters )
- {
- userOutputChannels = outputParameters->channelCount;
- outputSampleFormat = outputParameters->sampleFormat;
- /* unless alternate device specification is supported, reject the use of
- paUseHostApiSpecificDeviceSpecification */
- if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
- {
- PaWinWDM_SetLastErrorInfo(paInvalidDevice, "paUseHostApiSpecificDeviceSpecification(out) not supported");
- return paInvalidDevice;
- }
- /* check that output device can support stream->userInputChannels */
- if( userOutputChannels > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
- {
- PaWinWDM_SetLastErrorInfo(paInvalidChannelCount, "Invalid output channel count");
- return paInvalidChannelCount;
- }
- /* validate outputStreamInfo */
- result = ValidateSpecificStreamParameters( outputParameters, outputParameters->hostApiSpecificStreamInfo );
- if (result != paNoError)
- {
- PaWinWDM_SetLastErrorInfo(result, "Host API stream info not supported (out)");
- return result; /* this implementation doesn't use custom stream info */
- }
- }
- else
- {
- userOutputChannels = 0;
- outputSampleFormat = hostOutputSampleFormat = paInt16; /* Supress 'uninitialized var' warnings. */
- }
- /* validate platform specific flags */
- if( (streamFlags & paPlatformSpecificFlags) != 0 )
- {
- PaWinWDM_SetLastErrorInfo(paInvalidFlag, "Invalid flag supplied");
- return paInvalidFlag; /* unexpected platform specific flag */
- }
- stream = (PaWinWdmStream*)PaUtil_AllocateMemory( sizeof(PaWinWdmStream) );
- if( !stream )
- {
- result = paInsufficientMemory;
- goto error;
- }
- /* Create allocation group */
- stream->allocGroup = PaUtil_CreateAllocationGroup();
- if( !stream->allocGroup )
- {
- result = paInsufficientMemory;
- goto error;
- }
- /* Zero the stream object */
- /* memset((void*)stream,0,sizeof(PaWinWdmStream)); */
- if( streamCallback )
- {
- PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
- &wdmHostApi->callbackStreamInterface, streamCallback, userData );
- }
- else
- {
- /* PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
- &wdmHostApi->blockingStreamInterface, streamCallback, userData ); */
- /* We don't support the blocking API yet */
- PA_DEBUG(("Blocking API not supported yet!\n"));
- PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Blocking API not supported yet");
- result = paUnanticipatedHostError;
- goto error;
- }
- PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
- /* Instantiate the input pin if necessary */
- if(userInputChannels > 0)
- {
- PaWinWdmFilter* pFilter;
- PaWinWdmDeviceInfo* pDeviceInfo;
- PaWinWdmPin* pPin;
- unsigned validBitsPerSample = 0;
- PaWinWaveFormatChannelMask channelMask = PaWin_DefaultChannelMask( userInputChannels );
- result = paSampleFormatNotSupported;
- pDeviceInfo = (PaWinWdmDeviceInfo*)wdmHostApi->inheritedHostApiRep.deviceInfos[inputParameters->device];
- pFilter = pDeviceInfo->filter;
- pPin = pFilter->pins[pDeviceInfo->pin];
- stream->userInputChannels = userInputChannels;
- hostInputSampleFormat = PaUtil_SelectClosestAvailableFormat( pPin->formats, inputSampleFormat );
- if (hostInputSampleFormat == paSampleFormatNotSupported)
- {
- result = paUnanticipatedHostError;
- PaWinWDM_SetLastErrorInfo(result, "PU_SCAF(%X,%X) failed (input)", pPin->formats, inputSampleFormat);
- goto error;
- }
- else if (pFilter->devInfo.streamingType == Type_kWaveRT && hostInputSampleFormat == paInt24)
- {
- /* For WaveRT, we choose 32 bit format instead of paInt24, since we MIGHT need to align buffer on a
- 128 byte boundary (see PinGetBuffer) */
- hostInputSampleFormat = paInt32;
- /* But we'll tell the driver that it's 24 bit in 32 bit container */
- validBitsPerSample = 24;
- }
- while (hostInputSampleFormat <= paUInt8)
- {
- unsigned channelsToProbe = stream->userInputChannels;
- /* Some or all KS devices can only handle the exact number of channels
- * they specify. But PortAudio clients expect to be able to
- * at least specify mono I/O on a multi-channel device
- * If this is the case, then we will do the channel mapping internally
- * The following loop tests this case
- **/
- while (1)
- {
- PaWin_InitializeWaveFormatExtensible((PaWinWaveFormat*)&wfx,
- channelsToProbe,
- hostInputSampleFormat,
- PaWin_SampleFormatToLinearWaveFormatTag(hostInputSampleFormat),
- sampleRate,
- channelMask );
- stream->capture.bytesPerFrame = wfx.Format.nBlockAlign;
- if (validBitsPerSample != 0)
- {
- wfx.Samples.wValidBitsPerSample = validBitsPerSample;
- }
- stream->capture.pPin = FilterCreatePin(pFilter, pPin->pinId, (WAVEFORMATEX*)&wfx, &result);
- stream->deviceInputChannels = channelsToProbe;
- if( result != paNoError && result != paDeviceUnavailable )
- {
- /* Try a WAVE_FORMAT_PCM instead */
- PaWin_InitializeWaveFormatEx((PaWinWaveFormat*)&wfx,
- channelsToProbe,
- hostInputSampleFormat,
- PaWin_SampleFormatToLinearWaveFormatTag(hostInputSampleFormat),
- sampleRate);
- if (validBitsPerSample != 0)
- {
- wfx.Samples.wValidBitsPerSample = validBitsPerSample;
- }
- stream->capture.pPin = FilterCreatePin(pFilter, pPin->pinId, (const WAVEFORMATEX*)&wfx, &result);
- }
- if (result == paDeviceUnavailable) goto occupied;
- if (result == paNoError)
- {
- /* We're done */
- break;
- }
- if (channelsToProbe < (unsigned)pPin->maxChannels)
- {
- /* Go to next multiple of 2 */
- channelsToProbe = min((((channelsToProbe>>1)+1)<<1), (unsigned)pPin->maxChannels);
- continue;
- }
- break;
- }
- if (result == paNoError)
- {
- /* We're done */
- break;
- }
- /* Go to next format in line with lower resolution */
- hostInputSampleFormat <<= 1;
- }
- if(stream->capture.pPin == NULL)
- {
- PaWinWDM_SetLastErrorInfo(result, "Failed to create capture pin: sr=%u,ch=%u,bits=%u,align=%u",
- wfx.Format.nSamplesPerSec, wfx.Format.nChannels, wfx.Format.wBitsPerSample, wfx.Format.nBlockAlign);
- goto error;
- }
- /* Select correct mux input on MUX node of topology filter */
- if (pDeviceInfo->muxPosition >= 0)
- {
- assert(pPin->parentFilter->topologyFilter != NULL);
- result = FilterUse(pPin->parentFilter->topologyFilter);
- if (result != paNoError)
- {
- PaWinWDM_SetLastErrorInfo(result, "Failed to open topology filter");
- goto error;
- }
- result = WdmSetMuxNodeProperty(pPin->parentFilter->topologyFilter->handle,
- pPin->inputs[pDeviceInfo->muxPosition]->muxNodeId,
- pPin->inputs[pDeviceInfo->muxPosition]->muxPinId);
- FilterRelease(pPin->parentFilter->topologyFilter);
- if(result != paNoError)
- {
- PaWinWDM_SetLastErrorInfo(result, "Failed to set topology mux node");
- goto error;
- }
- }
- stream->capture.bytesPerSample = stream->capture.bytesPerFrame / stream->deviceInputChannels;
- stream->capture.pPin->frameSize /= stream->capture.bytesPerFrame;
- PA_DEBUG(("Capture pin frames: %d\n",stream->capture.pPin->frameSize));
- }
- else
- {
- stream->capture.pPin = NULL;
- stream->capture.bytesPerFrame = 0;
- }
- /* Instantiate the output pin if necessary */
- if(userOutputChannels > 0)
- {
- PaWinWdmFilter* pFilter;
- PaWinWdmDeviceInfo* pDeviceInfo;
- PaWinWdmPin* pPin;
- unsigned validBitsPerSample = 0;
- PaWinWaveFormatChannelMask channelMask = PaWin_DefaultChannelMask( userOutputChannels );
- result = paSampleFormatNotSupported;
- pDeviceInfo = (PaWinWdmDeviceInfo*)wdmHostApi->inheritedHostApiRep.deviceInfos[outputParameters->device];
- pFilter = pDeviceInfo->filter;
- pPin = pFilter->pins[pDeviceInfo->pin];
- stream->userOutputChannels = userOutputChannels;
- hostOutputSampleFormat = PaUtil_SelectClosestAvailableFormat( pPin->formats, outputSampleFormat );
- if (hostOutputSampleFormat == paSampleFormatNotSupported)
- {
- result = paUnanticipatedHostError;
- PaWinWDM_SetLastErrorInfo(result, "PU_SCAF(%X,%X) failed (output)", pPin->formats, hostOutputSampleFormat);
- goto error;
- }
- else if (pFilter->devInfo.streamingType == Type_kWaveRT && hostOutputSampleFormat == paInt24)
- {
- /* For WaveRT, we choose 32 bit format instead of paInt24, since we MIGHT need to align buffer on a
- 128 byte boundary (see PinGetBuffer) */
- hostOutputSampleFormat = paInt32;
- /* But we'll tell the driver that it's 24 bit in 32 bit container */
- validBitsPerSample = 24;
- }
- while (hostOutputSampleFormat <= paUInt8)
- {
- unsigned channelsToProbe = stream->userOutputChannels;
- /* Some or all KS devices can only handle the exact number of channels
- * they specify. But PortAudio clients expect to be able to
- * at least specify mono I/O on a multi-channel device
- * If this is the case, then we will do the channel mapping internally
- * The following loop tests this case
- **/
- while (1)
- {
- PaWin_InitializeWaveFormatExtensible((PaWinWaveFormat*)&wfx,
- channelsToProbe,
- hostOutputSampleFormat,
- PaWin_SampleFormatToLinearWaveFormatTag(hostOutputSampleFormat),
- sampleRate,
- channelMask );
- stream->render.bytesPerFrame = wfx.Format.nBlockAlign;
- if (validBitsPerSample != 0)
- {
- wfx.Samples.wValidBitsPerSample = validBitsPerSample;
- }
- stream->render.pPin = FilterCreatePin(pFilter, pPin->pinId, (WAVEFORMATEX*)&wfx, &result);
- stream->deviceOutputChannels = channelsToProbe;
- if( result != paNoError && result != paDeviceUnavailable )
- {
- PaWin_InitializeWaveFormatEx((PaWinWaveFormat*)&wfx,
- channelsToProbe,
- hostOutputSampleFormat,
- PaWin_SampleFormatToLinearWaveFormatTag(hostOutputSampleFormat),
- sampleRate);
- if (validBitsPerSample != 0)
- {
- wfx.Samples.wValidBitsPerSample = validBitsPerSample;
- }
- stream->render.pPin = FilterCreatePin(pFilter, pPin->pinId, (const WAVEFORMATEX*)&wfx, &result);
- }
- if (result == paDeviceUnavailable) goto occupied;
- if (result == paNoError)
- {
- /* We're done */
- break;
- }
- if (channelsToProbe < (unsigned)pPin->maxChannels)
- {
- /* Go to next multiple of 2 */
- channelsToProbe = min((((channelsToProbe>>1)+1)<<1), (unsigned)pPin->maxChannels);
- continue;
- }
- break;
- };
- if (result == paNoError)
- {
- /* We're done */
- break;
- }
- /* Go to next format in line with lower resolution */
- hostOutputSampleFormat <<= 1;
- }
- if(stream->render.pPin == NULL)
- {
- PaWinWDM_SetLastErrorInfo(result, "Failed to create render pin: sr=%u,ch=%u,bits=%u,align=%u",
- wfx.Format.nSamplesPerSec, wfx.Format.nChannels, wfx.Format.wBitsPerSample, wfx.Format.nBlockAlign);
- goto error;
- }
- stream->render.bytesPerSample = stream->render.bytesPerFrame / stream->deviceOutputChannels;
- stream->render.pPin->frameSize /= stream->render.bytesPerFrame;
- PA_DEBUG(("Render pin frames: %d\n",stream->render.pPin->frameSize));
- }
- else
- {
- stream->render.pPin = NULL;
- stream->render.bytesPerFrame = 0;
- }
- /* Calculate the framesPerHostXxxxBuffer size based upon the suggested latency values */
- /* Record the buffer length */
- if(inputParameters)
- {
- /* Calculate the frames from the user's value - add a bit to round up */
- stream->capture.framesPerBuffer = (unsigned long)((inputParameters->suggestedLatency*sampleRate)+0.0001);
- if(stream->capture.framesPerBuffer > (unsigned long)sampleRate)
- { /* Upper limit is 1 second */
- stream->capture.framesPerBuffer = (unsigned long)sampleRate;
- }
- else if(stream->capture.framesPerBuffer < stream->capture.pPin->frameSize)
- {
- stream->capture.framesPerBuffer = stream->capture.pPin->frameSize;
- }
- PA_DEBUG(("Input frames chosen:%ld\n",stream->capture.framesPerBuffer));
- /* Setup number of packets to use */
- stream->capture.noOfPackets = 2;
- if (inputParameters->hostApiSpecificStreamInfo)
- {
- PaWinWDMKSInfo* pInfo = (PaWinWDMKSInfo*)inputParameters->hostApiSpecificStreamInfo;
- if (stream->capture.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic &&
- pInfo->noOfPackets != 0)
- {
- stream->capture.noOfPackets = pInfo->noOfPackets;
- }
- }
- }
- if(outputParameters)
- {
- /* Calculate the frames from the user's value - add a bit to round up */
- stream->render.framesPerBuffer = (unsigned long)((outputParameters->suggestedLatency*sampleRate)+0.0001);
- if(stream->render.framesPerBuffer > (unsigned long)sampleRate)
- { /* Upper limit is 1 second */
- stream->render.framesPerBuffer = (unsigned long)sampleRate;
- }
- else if(stream->render.framesPerBuffer < stream->render.pPin->frameSize)
- {
- stream->render.framesPerBuffer = stream->render.pPin->frameSize;
- }
- PA_DEBUG(("Output frames chosen:%ld\n",stream->render.framesPerBuffer));
- /* Setup number of packets to use */
- stream->render.noOfPackets = 2;
- if (outputParameters->hostApiSpecificStreamInfo)
- {
- PaWinWDMKSInfo* pInfo = (PaWinWDMKSInfo*)outputParameters->hostApiSpecificStreamInfo;
- if (stream->render.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic &&
- pInfo->noOfPackets != 0)
- {
- stream->render.noOfPackets = pInfo->noOfPackets;
- }
- }
- }
- /* Host buffer size is bound to the largest of the input and output frame sizes */
- result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
- stream->userInputChannels, inputSampleFormat, hostInputSampleFormat,
- stream->userOutputChannels, outputSampleFormat, hostOutputSampleFormat,
- sampleRate, streamFlags, framesPerUserBuffer,
- max(stream->capture.framesPerBuffer, stream->render.framesPerBuffer),
- paUtilBoundedHostBufferSize,
- streamCallback, userData );
- if( result != paNoError )
- {
- PaWinWDM_SetLastErrorInfo(result, "PaUtil_InitializeBufferProcessor failed: ich=%u, isf=%u, hisf=%u, och=%u, osf=%u, hosf=%u, sr=%lf, flags=0x%X, fpub=%u, fphb=%u",
- stream->userInputChannels, inputSampleFormat, hostInputSampleFormat,
- stream->userOutputChannels, outputSampleFormat, hostOutputSampleFormat,
- sampleRate, streamFlags, framesPerUserBuffer,
- max(stream->capture.framesPerBuffer, stream->render.framesPerBuffer));
- goto error;
- }
- /* Allocate/get all the buffers for host I/O */
- if (stream->userInputChannels > 0)
- {
- stream->streamRepresentation.streamInfo.inputLatency = stream->capture.framesPerBuffer / sampleRate;
- switch (stream->capture.pPin->parentFilter->devInfo.streamingType)
- {
- case Type_kWaveCyclic:
- {
- unsigned size = stream->capture.noOfPackets * stream->capture.framesPerBuffer * stream->capture.bytesPerFrame;
- /* Allocate input host buffer */
- stream->capture.hostBuffer = (char*)PaUtil_GroupAllocateMemory(stream->allocGroup, size);
- PA_DEBUG(("Input buffer allocated (size = %u)\n", size));
- if( !stream->capture.hostBuffer )
- {
- PA_DEBUG(("Cannot allocate host input buffer!\n"));
- PaWinWDM_SetLastErrorInfo(paInsufficientMemory, "Failed to allocate input buffer");
- result = paInsufficientMemory;
- goto error;
- }
- stream->capture.hostBufferSize = size;
- PA_DEBUG(("Input buffer start = %p (size=%u)\n",stream->capture.hostBuffer, stream->capture.hostBufferSize));
- stream->capture.pPin->fnEventHandler = PaPinCaptureEventHandler_WaveCyclic;
- stream->capture.pPin->fnSubmitHandler = PaPinCaptureSubmitHandler_WaveCyclic;
- }
- break;
- case Type_kWaveRT:
- {
- const DWORD dwTotalSize = 2 * stream->capture.framesPerBuffer * stream->capture.bytesPerFrame;
- DWORD dwRequestedSize = dwTotalSize;
- BOOL bCallMemoryBarrier = FALSE;
- ULONG hwFifoLatency = 0;
- ULONG dummy;
- result = PinGetBuffer(stream->capture.pPin, (void**)&stream->capture.hostBuffer, &dwRequestedSize, &bCallMemoryBarrier);
- if (!result)
- {
- PA_DEBUG(("Input buffer start = %p, size = %u\n", stream->capture.hostBuffer, dwRequestedSize));
- if (dwRequestedSize != dwTotalSize)
- {
- PA_DEBUG(("Buffer length changed by driver from %u to %u !\n", dwTotalSize, dwRequestedSize));
- /* Recalculate to what the driver has given us */
- stream->capture.framesPerBuffer = dwRequestedSize / (2 * stream->capture.bytesPerFrame);
- }
- stream->capture.hostBufferSize = dwRequestedSize;
- if (stream->capture.pPin->pinKsSubType == SubType_kPolled)
- {
- stream->capture.pPin->fnEventHandler = PaPinCaptureEventHandler_WaveRTPolled;
- stream->capture.pPin->fnSubmitHandler = PaPinCaptureSubmitHandler_WaveRTPolled;
- }
- else
- {
- stream->capture.pPin->fnEventHandler = PaPinCaptureEventHandler_WaveRTEvent;
- stream->capture.pPin->fnSubmitHandler = PaPinCaptureSubmitHandler_WaveRTEvent;
- }
- stream->capture.pPin->fnMemBarrier = bCallMemoryBarrier ? MemoryBarrierRead : MemoryBarrierDummy;
- }
- else
- {
- PA_DEBUG(("Failed to get input buffer (WaveRT)\n"));
- PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to get input buffer (WaveRT)");
- result = paUnanticipatedHostError;
- goto error;
- }
- /* Get latency */
- result = PinGetHwLatency(stream->capture.pPin, &hwFifoLatency, &dummy, &dummy);
- if (result == paNoError)
- {
- stream->capture.pPin->hwLatency = hwFifoLatency;
- /* Add HW latency into total input latency */
- stream->streamRepresentation.streamInfo.inputLatency += ((hwFifoLatency / stream->capture.bytesPerFrame) / sampleRate);
- }
- else
- {
- PA_DEBUG(("Failed to get size of FIFO hardware buffer (is set to zero)\n"));
- stream->capture.pPin->hwLatency = 0;
- }
- }
- break;
- default:
- /* Undefined wave type!! */
- assert(0);
- result = paInternalError;
- PaWinWDM_SetLastErrorInfo(result, "Wave type %u ??", stream->capture.pPin->parentFilter->devInfo.streamingType);
- goto error;
- }
- }
- else
- {
- stream->capture.hostBuffer = 0;
- }
- if (stream->userOutputChannels > 0)
- {
- stream->streamRepresentation.streamInfo.outputLatency = stream->render.framesPerBuffer / sampleRate;
- switch (stream->render.pPin->parentFilter->devInfo.streamingType)
- {
- case Type_kWaveCyclic:
- {
- unsigned size = stream->render.noOfPackets * stream->render.framesPerBuffer * stream->render.bytesPerFrame;
- /* Allocate output device buffer */
- stream->render.hostBuffer = (char*)PaUtil_GroupAllocateMemory(stream->allocGroup, size);
- PA_DEBUG(("Output buffer allocated (size = %u)\n", size));
- if( !stream->render.hostBuffer )
- {
- PA_DEBUG(("Cannot allocate host output buffer!\n"));
- PaWinWDM_SetLastErrorInfo(paInsufficientMemory, "Failed to allocate output buffer");
- result = paInsufficientMemory;
- goto error;
- }
- stream->render.hostBufferSize = size;
- PA_DEBUG(("Output buffer start = %p (size=%u)\n",stream->render.hostBuffer, stream->render.hostBufferSize));
- stream->render.pPin->fnEventHandler = PaPinRenderEventHandler_WaveCyclic;
- stream->render.pPin->fnSubmitHandler = PaPinRenderSubmitHandler_WaveCyclic;
- }
- break;
- case Type_kWaveRT:
- {
- const DWORD dwTotalSize = 2 * stream->render.framesPerBuffer * stream->render.bytesPerFrame;
- DWORD dwRequestedSize = dwTotalSize;
- BOOL bCallMemoryBarrier = FALSE;
- ULONG hwFifoLatency = 0;
- ULONG dummy;
- result = PinGetBuffer(stream->render.pPin, (void**)&stream->render.hostBuffer, &dwRequestedSize, &bCallMemoryBarrier);
- if (!result)
- {
- PA_DEBUG(("Output buffer start = %p, size = %u, membarrier = %u\n", stream->render.hostBuffer, dwRequestedSize, bCallMemoryBarrier));
- if (dwRequestedSize != dwTotalSize)
- {
- PA_DEBUG(("Buffer length changed by driver from %u to %u !\n", dwTotalSize, dwRequestedSize));
- /* Recalculate to what the driver has given us */
- stream->render.framesPerBuffer = dwRequestedSize / (2 * stream->render.bytesPerFrame);
- }
- stream->render.hostBufferSize = dwRequestedSize;
- if (stream->render.pPin->pinKsSubType == SubType_kPolled)
- {
- stream->render.pPin->fnEventHandler = PaPinRenderEventHandler_WaveRTPolled;
- stream->render.pPin->fnSubmitHandler = PaPinRenderSubmitHandler_WaveRTPolled;
- }
- else
- {
- stream->render.pPin->fnEventHandler = PaPinRenderEventHandler_WaveRTEvent;
- stream->render.pPin->fnSubmitHandler = PaPinRenderSubmitHandler_WaveRTEvent;
- }
- stream->render.pPin->fnMemBarrier = bCallMemoryBarrier ? MemoryBarrierWrite : MemoryBarrierDummy;
- }
- else
- {
- PA_DEBUG(("Failed to get output buffer (with notification)\n"));
- PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to get output buffer (with notification)");
- result = paUnanticipatedHostError;
- goto error;
- }
- /* Get latency */
- result = PinGetHwLatency(stream->render.pPin, &hwFifoLatency, &dummy, &dummy);
- if (result == paNoError)
- {
- stream->render.pPin->hwLatency = hwFifoLatency;
- /* Add HW latency into total output latency */
- stream->streamRepresentation.streamInfo.outputLatency += ((hwFifoLatency / stream->render.bytesPerFrame) / sampleRate);
- }
- else
- {
- PA_DEBUG(("Failed to get size of FIFO hardware buffer (is set to zero)\n"));
- stream->render.pPin->hwLatency = 0;
- }
- }
- break;
- default:
- /* Undefined wave type!! */
- assert(0);
- result = paInternalError;
- PaWinWDM_SetLastErrorInfo(result, "Wave type %u ??", stream->capture.pPin->parentFilter->devInfo.streamingType);
- goto error;
- }
- }
- else
- {
- stream->render.hostBuffer = 0;
- }
- stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
- PA_DEBUG(("BytesPerInputFrame = %d\n",stream->capture.bytesPerFrame));
- PA_DEBUG(("BytesPerOutputFrame = %d\n",stream->render.bytesPerFrame));
- /* memset(stream->hostBuffer,0,size); */
- /* Abort */
- stream->eventAbort = CreateEvent(NULL, TRUE, FALSE, NULL);
- if (stream->eventAbort == 0)
- {
- result = paInsufficientMemory;
- goto error;
- }
- stream->eventStreamStart[0] = CreateEvent(NULL, TRUE, FALSE, NULL);
- if (stream->eventStreamStart[0] == 0)
- {
- result = paInsufficientMemory;
- goto error;
- }
- stream->eventStreamStart[1] = CreateEvent(NULL, TRUE, FALSE, NULL);
- if (stream->eventStreamStart[1] == 0)
- {
- result = paInsufficientMemory;
- goto error;
- }
- if(stream->userInputChannels > 0)
- {
- const unsigned bufferSizeInBytes = stream->capture.framesPerBuffer * stream->capture.bytesPerFrame;
- const unsigned ringBufferFrameSize = NextPowerOf2( 1024 + 2 * max(stream->capture.framesPerBuffer, stream->render.framesPerBuffer) );
- stream->capture.events = (HANDLE*)PaUtil_GroupAllocateMemory(stream->allocGroup, stream->capture.noOfPackets * sizeof(HANDLE));
- if (stream->capture.events == NULL)
- {
- result = paInsufficientMemory;
- goto error;
- }
- stream->capture.packets = (DATAPACKET*)PaUtil_GroupAllocateMemory(stream->allocGroup, stream->capture.noOfPackets * sizeof(DATAPACKET));
- if (stream->capture.packets == NULL)
- {
- result = paInsufficientMemory;
- goto error;
- }
- switch(stream->capture.pPin->parentFilter->devInfo.streamingType)
- {
- case Type_kWaveCyclic:
- {
- /* WaveCyclic case */
- unsigned i;
- for (i = 0; i < stream->capture.noOfPackets; ++i)
- {
- /* Set up the packets */
- DATAPACKET *p = stream->capture.packets + i;
- /* Record event */
- stream->capture.events[i] = CreateEvent(NULL, TRUE, FALSE, NULL);
- p->Signal.hEvent = stream->capture.events[i];
- p->Header.Data = stream->capture.hostBuffer + (i*bufferSizeInBytes);
- p->Header.FrameExtent = bufferSizeInBytes;
- p->Header.DataUsed = 0;
- p->Header.Size = sizeof(p->Header);
- p->Header.PresentationTime.Numerator = 1;
- p->Header.PresentationTime.Denominator = 1;
- }
- }
- break;
- case Type_kWaveRT:
- {
- /* Set up the "packets" */
- DATAPACKET *p = stream->capture.packets + 0;
- /* Record event: WaveRT has a single event for 2 notification per buffer */
- stream->capture.events[0] = CreateEvent(NULL, FALSE, FALSE, NULL);
- p->Header.Data = stream->capture.hostBuffer;
- p->Header.FrameExtent = bufferSizeInBytes;
- p->Header.DataUsed = 0;
- p->Header.Size = sizeof(p->Header);
- p->Header.PresentationTime.Numerator = 1;
- p->Header.PresentationTime.Denominator = 1;
- ++p;
- p->Header.Data = stream->capture.hostBuffer + bufferSizeInBytes;
- p->Header.FrameExtent = bufferSizeInBytes;
- p->Header.DataUsed = 0;
- p->Header.Size = sizeof(p->Header);
- p->Header.PresentationTime.Numerator = 1;
- p->Header.PresentationTime.Denominator = 1;
- if (stream->capture.pPin->pinKsSubType == SubType_kNotification)
- {
- result = PinRegisterNotificationHandle(stream->capture.pPin, stream->capture.events[0]);
- if (result != paNoError)
- {
- PA_DEBUG(("Failed to register capture notification handle\n"));
- PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to register capture notification handle");
- result = paUnanticipatedHostError;
- goto error;
- }
- }
- result = PinRegisterPositionRegister(stream->capture.pPin);
- if (result != paNoError)
- {
- unsigned long pos = 0xdeadc0de;
- PA_DEBUG(("Failed to register capture position register, using PinGetAudioPositionViaIOCTL\n"));
- stream->capture.pPin->fnAudioPosition = PinGetAudioPositionViaIOCTL;
- /* Test position function */
- result = (stream->capture.pPin->fnAudioPosition)(stream->capture.pPin, &pos);
- if (result != paNoError || pos != 0x0)
- {
- PA_DEBUG(("Failed to read capture position register (IOCTL)\n"));
- PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to read capture position register (IOCTL)");
- result = paUnanticipatedHostError;
- goto error;
- }
- }
- else
- {
- stream->capture.pPin->fnAudioPosition = PinGetAudioPositionDirect;
- }
- }
- break;
- default:
- /* Undefined wave type!! */
- assert(0);
- result = paInternalError;
- PaWinWDM_SetLastErrorInfo(result, "Wave type %u ??", stream->capture.pPin->parentFilter->devInfo.streamingType);
- goto error;
- }
- /* Setup the input ring buffer here */
- stream->ringBufferData = (char*)PaUtil_GroupAllocateMemory(stream->allocGroup, ringBufferFrameSize * stream->capture.bytesPerFrame);
- if (stream->ringBufferData == NULL)
- {
- result = paInsufficientMemory;
- goto error;
- }
- PaUtil_InitializeRingBuffer(&stream->ringBuffer, stream->capture.bytesPerFrame, ringBufferFrameSize, stream->ringBufferData);
- }
- if(stream->userOutputChannels > 0)
- {
- const unsigned bufferSizeInBytes = stream->render.framesPerBuffer * stream->render.bytesPerFrame;
- stream->render.events = (HANDLE*)PaUtil_GroupAllocateMemory(stream->allocGroup, stream->render.noOfPackets * sizeof(HANDLE));
- if (stream->render.events == NULL)
- {
- result = paInsufficientMemory;
- goto error;
- }
- stream->render.packets = (DATAPACKET*)PaUtil_GroupAllocateMemory(stream->allocGroup, stream->render.noOfPackets * sizeof(DATAPACKET));
- if (stream->render.packets == NULL)
- {
- result = paInsufficientMemory;
- goto error;
- }
- switch(stream->render.pPin->parentFilter->devInfo.streamingType)
- {
- case Type_kWaveCyclic:
- {
- /* WaveCyclic case */
- unsigned i;
- for (i = 0; i < stream->render.noOfPackets; ++i)
- {
- /* Set up the packets */
- DATAPACKET *p = stream->render.packets + i;
- /* Playback event */
- stream->render.events[i] = CreateEvent(NULL, TRUE, FALSE, NULL);
- /* In this case, we just use the packets as ptr to the device buffer */
- p->Signal.hEvent = stream->render.events[i];
- p->Header.Data = stream->render.hostBuffer + (i*bufferSizeInBytes);
- p->Header.FrameExtent = bufferSizeInBytes;
- p->Header.DataUsed = bufferSizeInBytes;
- p->Header.Size = sizeof(p->Header);
- p->Header.PresentationTime.Numerator = 1;
- p->Header.PresentationTime.Denominator = 1;
- }
- }
- break;
- case Type_kWaveRT:
- {
- /* WaveRT case */
- /* Set up the "packets" */
- DATAPACKET *p = stream->render.packets;
- /* The only playback event */
- stream->render.events[0] = CreateEvent(NULL, FALSE, FALSE, NULL);
- /* In this case, we just use the packets as ptr to the device buffer */
- p->Header.Data = stream->render.hostBuffer;
- p->Header.FrameExtent = stream->render.framesPerBuffer*stream->render.bytesPerFrame;
- p->Header.DataUsed = stream->render.framesPerBuffer*stream->render.bytesPerFrame;
- p->Header.Size = sizeof(p->Header);
- p->Header.PresentationTime.Numerator = 1;
- p->Header.PresentationTime.Denominator = 1;
- ++p;
- p->Header.Data = stream->render.hostBuffer + stream->render.framesPerBuffer*stream->render.bytesPerFrame;
- p->Header.FrameExtent = stream->render.framesPerBuffer*stream->render.bytesPerFrame;
- p->Header.DataUsed = stream->render.framesPerBuffer*stream->render.bytesPerFrame;
- p->Header.Size = sizeof(p->Header);
- p->Header.PresentationTime.Numerator = 1;
- p->Header.PresentationTime.Denominator = 1;
- if (stream->render.pPin->pinKsSubType == SubType_kNotification)
- {
- result = PinRegisterNotificationHandle(stream->render.pPin, stream->render.events[0]);
- if (result != paNoError)
- {
- PA_DEBUG(("Failed to register rendering notification handle\n"));
- PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to register rendering notification handle");
- result = paUnanticipatedHostError;
- goto error;
- }
- }
- result = PinRegisterPositionRegister(stream->render.pPin);
- if (result != paNoError)
- {
- unsigned long pos = 0xdeadc0de;
- PA_DEBUG(("Failed to register rendering position register, using PinGetAudioPositionViaIOCTL\n"));
- stream->render.pPin->fnAudioPosition = PinGetAudioPositionViaIOCTL;
- /* Test position function */
- result = (stream->render.pPin->fnAudioPosition)(stream->render.pPin, &pos);
- if (result != paNoError || pos != 0x0)
- {
- PA_DEBUG(("Failed to read render position register (IOCTL)\n"));
- PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to read render position register (IOCTL)");
- result = paUnanticipatedHostError;
- goto error;
- }
- }
- else
- {
- stream->render.pPin->fnAudioPosition = PinGetAudioPositionDirect;
- }
- }
- break;
- default:
- /* Undefined wave type!! */
- assert(0);
- result = paInternalError;
- PaWinWDM_SetLastErrorInfo(result, "Wave type %u ??", stream->capture.pPin->parentFilter->devInfo.streamingType);
- goto error;
- }
- }
- stream->streamStarted = 0;
- stream->streamActive = 0;
- stream->streamStop = 0;
- stream->streamAbort = 0;
- stream->streamFlags = streamFlags;
- stream->oldProcessPriority = REALTIME_PRIORITY_CLASS;
- /* Increase ref count on filters in use, so that a CommitDeviceInfos won't delete them */
- if (stream->capture.pPin != 0)
- {
- FilterAddRef(stream->capture.pPin->parentFilter);
- }
- if (stream->render.pPin != 0)
- {
- FilterAddRef(stream->render.pPin->parentFilter);
- }
- /* Ok, now update our host API specific stream info */
- if (stream->userInputChannels)
- {
- PaWinWdmDeviceInfo *pDeviceInfo = (PaWinWdmDeviceInfo*)wdmHostApi->inheritedHostApiRep.deviceInfos[inputParameters->device];
- stream->hostApiStreamInfo.input.device = Pa_HostApiDeviceIndexToDeviceIndex(Pa_HostApiTypeIdToHostApiIndex(paWDMKS), inputParameters->device);
- stream->hostApiStreamInfo.input.channels = stream->deviceInputChannels;
- stream->hostApiStreamInfo.input.muxNodeId = -1;
- if (stream->capture.pPin->inputs)
- {
- stream->hostApiStreamInfo.input.muxNodeId = stream->capture.pPin->inputs[pDeviceInfo->muxPosition]->muxNodeId;
- }
- stream->hostApiStreamInfo.input.endpointPinId = pDeviceInfo->endpointPinId;
- stream->hostApiStreamInfo.input.framesPerHostBuffer = stream->capture.framesPerBuffer;
- stream->hostApiStreamInfo.input.streamingSubType = stream->capture.pPin->pinKsSubType;
- }
- else
- {
- stream->hostApiStreamInfo.input.device = paNoDevice;
- }
- if (stream->userOutputChannels)
- {
- stream->hostApiStreamInfo.output.device = Pa_HostApiDeviceIndexToDeviceIndex(Pa_HostApiTypeIdToHostApiIndex(paWDMKS), outputParameters->device);
- stream->hostApiStreamInfo.output.channels = stream->deviceOutputChannels;
- stream->hostApiStreamInfo.output.framesPerHostBuffer = stream->render.framesPerBuffer;
- stream->hostApiStreamInfo.output.endpointPinId = stream->render.pPin->endpointPinId;
- stream->hostApiStreamInfo.output.streamingSubType = stream->render.pPin->pinKsSubType;
- }
- else
- {
- stream->hostApiStreamInfo.output.device = paNoDevice;
- }
- /*stream->streamRepresentation.streamInfo.hostApiTypeId = paWDMKS;
- stream->streamRepresentation.streamInfo.hostApiSpecificStreamInfo = &stream->hostApiStreamInfo;*/
- stream->streamRepresentation.streamInfo.structVersion = 2;
- *s = (PaStream*)stream;
- PA_LOGL_;
- return result;
- occupied:
- /* Ok, someone else is hogging the pin, bail out */
- assert (result == paDeviceUnavailable);
- PaWinWDM_SetLastErrorInfo(result, "Device is occupied");
- error:
- PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
- CloseStreamEvents(stream);
- if (stream->allocGroup)
- {
- PaUtil_FreeAllAllocations(stream->allocGroup);
- PaUtil_DestroyAllocationGroup(stream->allocGroup);
- stream->allocGroup = 0;
- }
- if(stream->render.pPin)
- PinClose(stream->render.pPin);
- if(stream->capture.pPin)
- PinClose(stream->capture.pPin);
- PaUtil_FreeMemory( stream );
- PA_LOGL_;
- return result;
- }
- /*
- When CloseStream() is called, the multi-api layer ensures that
- the stream has already been stopped or aborted.
- */
- static PaError CloseStream( PaStream* s )
- {
- PaError result = paNoError;
- PaWinWdmStream *stream = (PaWinWdmStream*)s;
- PA_LOGE_;
- assert(!stream->streamStarted);
- assert(!stream->streamActive);
- PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
- PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
- CloseStreamEvents(stream);
- if (stream->allocGroup)
- {
- PaUtil_FreeAllAllocations(stream->allocGroup);
- PaUtil_DestroyAllocationGroup(stream->allocGroup);
- stream->allocGroup = 0;
- }
- if(stream->render.pPin)
- {
- PinClose(stream->render.pPin);
- }
- if(stream->capture.pPin)
- {
- PinClose(stream->capture.pPin);
- }
- if (stream->render.pPin)
- {
- FilterFree(stream->render.pPin->parentFilter);
- }
- if (stream->capture.pPin)
- {
- FilterFree(stream->capture.pPin->parentFilter);
- }
- PaUtil_FreeMemory( stream );
- PA_LOGL_;
- return result;
- }
- /*
- Write the supplied packet to the pin
- Asynchronous
- Should return paNoError on success
- */
- static PaError PinWrite(HANDLE h, DATAPACKET* p)
- {
- PaError result = paNoError;
- unsigned long cbReturned = 0;
- BOOL fRes = DeviceIoControl(h,
- IOCTL_KS_WRITE_STREAM,
- NULL,
- 0,
- &p->Header,
- p->Header.Size,
- &cbReturned,
- &p->Signal);
- if (!fRes)
- {
- unsigned long error = GetLastError();
- if (error != ERROR_IO_PENDING)
- {
- result = paInternalError;
- }
- }
- return result;
- }
- /*
- Read to the supplied packet from the pin
- Asynchronous
- Should return paNoError on success
- */
- static PaError PinRead(HANDLE h, DATAPACKET* p)
- {
- PaError result = paNoError;
- unsigned long cbReturned = 0;
- BOOL fRes = DeviceIoControl(h,
- IOCTL_KS_READ_STREAM,
- NULL,
- 0,
- &p->Header,
- p->Header.Size,
- &cbReturned,
- &p->Signal);
- if (!fRes)
- {
- unsigned long error = GetLastError();
- if (error != ERROR_IO_PENDING)
- {
- result = paInternalError;
- }
- }
- return result;
- }
- /*
- Copy the first interleaved channel of 16 bit data to the other channels
- */
- static void DuplicateFirstChannelInt16(void* buffer, int channels, int samples)
- {
- unsigned short* data = (unsigned short*)buffer;
- int channel;
- unsigned short sourceSample;
- while( samples-- )
- {
- sourceSample = *data++;
- channel = channels-1;
- while( channel-- )
- {
- *data++ = sourceSample;
- }
- }
- }
- /*
- Copy the first interleaved channel of 24 bit data to the other channels
- */
- static void DuplicateFirstChannelInt24(void* buffer, int channels, int samples)
- {
- unsigned char* data = (unsigned char*)buffer;
- int channel;
- unsigned char sourceSample[3];
- while( samples-- )
- {
- sourceSample[0] = data[0];
- sourceSample[1] = data[1];
- sourceSample[2] = data[2];
- data += 3;
- channel = channels-1;
- while( channel-- )
- {
- data[0] = sourceSample[0];
- data[1] = sourceSample[1];
- data[2] = sourceSample[2];
- data += 3;
- }
- }
- }
- /*
- Copy the first interleaved channel of 32 bit data to the other channels
- */
- static void DuplicateFirstChannelInt32(void* buffer, int channels, int samples)
- {
- unsigned long* data = (unsigned long*)buffer;
- int channel;
- unsigned long sourceSample;
- while( samples-- )
- {
- sourceSample = *data++;
- channel = channels-1;
- while( channel-- )
- {
- *data++ = sourceSample;
- }
- }
- }
- /*
- Increase the priority of the calling thread to RT
- */
- static HANDLE BumpThreadPriority()
- {
- HANDLE hThread = GetCurrentThread();
- DWORD dwTask = 0;
- HANDLE hAVRT = NULL;
- /* If we have access to AVRT.DLL (Vista and later), use it */
- if (paWinWDMKSAvRtEntryPoints.AvSetMmThreadCharacteristics != NULL)
- {
- hAVRT = paWinWDMKSAvRtEntryPoints.AvSetMmThreadCharacteristics("Pro Audio", &dwTask);
- if (hAVRT != NULL && hAVRT != INVALID_HANDLE_VALUE)
- {
- BOOL bret = paWinWDMKSAvRtEntryPoints.AvSetMmThreadPriority(hAVRT, PA_AVRT_PRIORITY_CRITICAL);
- if (!bret)
- {
- PA_DEBUG(("Set mm thread prio to critical failed!\n"));
- }
- else
- {
- return hAVRT;
- }
- }
- else
- {
- PA_DEBUG(("Set mm thread characteristic to 'Pro Audio' failed, reverting to SetThreadPriority\n"));
- }
- }
- /* For XP and earlier, or if AvSetMmThreadCharacteristics fails (MMCSS disabled ?) */
- if (timeBeginPeriod(1) != TIMERR_NOERROR) {
- PA_DEBUG(("timeBeginPeriod(1) failed!\n"));
- }
- if (!SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL)) {
- PA_DEBUG(("SetThreadPriority failed!\n"));
- }
- return hAVRT;
- }
- /*
- Decrease the priority of the calling thread to normal
- */
- static void DropThreadPriority(HANDLE hAVRT)
- {
- HANDLE hThread = GetCurrentThread();
- if (hAVRT != NULL)
- {
- paWinWDMKSAvRtEntryPoints.AvSetMmThreadPriority(hAVRT, PA_AVRT_PRIORITY_NORMAL);
- paWinWDMKSAvRtEntryPoints.AvRevertMmThreadCharacteristics(hAVRT);
- return;
- }
- SetThreadPriority(hThread, THREAD_PRIORITY_NORMAL);
- timeEndPeriod(1);
- }
- static PaError PreparePinForStart(PaWinWdmPin* pin)
- {
- PaError result;
- result = PinSetState(pin, KSSTATE_ACQUIRE);
- if (result != paNoError)
- {
- goto error;
- }
- result = PinSetState(pin, KSSTATE_PAUSE);
- if (result != paNoError)
- {
- goto error;
- }
- return result;
- error:
- PinSetState(pin, KSSTATE_STOP);
- return result;
- }
- static PaError PreparePinsForStart(PaProcessThreadInfo* pInfo)
- {
- PaError result = paNoError;
- /* Submit buffers */
- if (pInfo->stream->capture.pPin)
- {
- if ((result = PreparePinForStart(pInfo->stream->capture.pPin)) != paNoError)
- {
- goto error;
- }
- if (pInfo->stream->capture.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic)
- {
- unsigned i;
- for(i=0; i < pInfo->stream->capture.noOfPackets; ++i)
- {
- if ((result = PinRead(pInfo->stream->capture.pPin->handle, pInfo->stream->capture.packets + i)) != paNoError)
- {
- goto error;
- }
- ++pInfo->pending;
- }
- }
- else
- {
- pInfo->pending = 2;
- }
- }
- if(pInfo->stream->render.pPin)
- {
- if ((result = PreparePinForStart(pInfo->stream->render.pPin)) != paNoError)
- {
- goto error;
- }
- pInfo->priming += pInfo->stream->render.noOfPackets;
- ++pInfo->pending;
- SetEvent(pInfo->stream->render.events[0]);
- if (pInfo->stream->render.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic)
- {
- unsigned i;
- for(i=1; i < pInfo->stream->render.noOfPackets; ++i)
- {
- SetEvent(pInfo->stream->render.events[i]);
- ++pInfo->pending;
- }
- }
- }
- error:
- PA_DEBUG(("PreparePinsForStart = %d\n", result));
- return result;
- }
- static PaError StartPin(PaWinWdmPin* pin)
- {
- return PinSetState(pin, KSSTATE_RUN);
- }
- static PaError StartPins(PaProcessThreadInfo* pInfo)
- {
- PaError result = paNoError;
- /* Start the pins as synced as possible */
- if (pInfo->stream->capture.pPin)
- {
- result = StartPin(pInfo->stream->capture.pPin);
- }
- if(pInfo->stream->render.pPin)
- {
- result = StartPin(pInfo->stream->render.pPin);
- }
- PA_DEBUG(("StartPins = %d\n", result));
- return result;
- }
- static PaError StopPin(PaWinWdmPin* pin)
- {
- PinSetState(pin, KSSTATE_PAUSE);
- PinSetState(pin, KSSTATE_STOP);
- return paNoError;
- }
- static PaError StopPins(PaProcessThreadInfo* pInfo)
- {
- PaError result = paNoError;
- if(pInfo->stream->render.pPin)
- {
- StopPin(pInfo->stream->render.pPin);
- }
- if(pInfo->stream->capture.pPin)
- {
- StopPin(pInfo->stream->capture.pPin);
- }
- return result;
- }
- typedef void (*TSetInputFrameCount)(PaUtilBufferProcessor*, unsigned long);
- typedef void (*TSetInputChannel)(PaUtilBufferProcessor*, unsigned int, void *, unsigned int);
- static const TSetInputFrameCount fnSetInputFrameCount[2] = { PaUtil_SetInputFrameCount, PaUtil_Set2ndInputFrameCount };
- static const TSetInputChannel fnSetInputChannel[2] = { PaUtil_SetInputChannel, PaUtil_Set2ndInputChannel };
- static PaError PaDoProcessing(PaProcessThreadInfo* pInfo)
- {
- PaError result = paNoError;
- int i, framesProcessed = 0, doChannelCopy = 0;
- ring_buffer_size_t inputFramesAvailable = PaUtil_GetRingBufferReadAvailable(&pInfo->stream->ringBuffer);
- /* Do necessary buffer processing (which will invoke user callback if necessary) */
- if (pInfo->cbResult == paContinue &&
- (pInfo->renderHead != pInfo->renderTail || inputFramesAvailable))
- {
- unsigned processFullDuplex = pInfo->stream->capture.pPin && pInfo->stream->render.pPin && (!pInfo->priming);
- PA_HP_TRACE((pInfo->stream->hLog, "DoProcessing: InputFrames=%u", inputFramesAvailable));
- PaUtil_BeginCpuLoadMeasurement( &pInfo->stream->cpuLoadMeasurer );
- pInfo->ti.currentTime = PaUtil_GetTime();
- PaUtil_BeginBufferProcessing(&pInfo->stream->bufferProcessor, &pInfo->ti, pInfo->underover);
- pInfo->underover = 0; /* Reset the (under|over)flow status */
- if (pInfo->renderTail != pInfo->renderHead)
- {
- DATAPACKET* packet = pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet;
- assert(packet != 0);
- assert(packet->Header.Data != 0);
- PaUtil_SetOutputFrameCount(&pInfo->stream->bufferProcessor, pInfo->stream->render.framesPerBuffer);
- for(i=0;i<pInfo->stream->userOutputChannels;i++)
- {
- /* Only write the user output channels. Leave the rest blank */
- PaUtil_SetOutputChannel(&pInfo->stream->bufferProcessor,
- i,
- ((unsigned char*)(packet->Header.Data))+(i*pInfo->stream->render.bytesPerSample),
- pInfo->stream->deviceOutputChannels);
- }
- /* We will do a copy to the other channels after the data has been written */
- doChannelCopy = ( pInfo->stream->userOutputChannels == 1 );
- }
- if (inputFramesAvailable && (!pInfo->stream->userOutputChannels || inputFramesAvailable >= (int)pInfo->stream->render.framesPerBuffer))
- {
- unsigned wrapCntr = 0;
- void* data[2] = {0};
- ring_buffer_size_t size[2] = {0};
- /* If full-duplex, we just extract output buffer number of frames */
- if (pInfo->stream->userOutputChannels)
- {
- inputFramesAvailable = min(inputFramesAvailable, (int)pInfo->stream->render.framesPerBuffer);
- }
- inputFramesAvailable = PaUtil_GetRingBufferReadRegions(&pInfo->stream->ringBuffer,
- inputFramesAvailable,
- &data[0],
- &size[0],
- &data[1],
- &size[1]);
- for (wrapCntr = 0; wrapCntr < 2; ++wrapCntr)
- {
- if (size[wrapCntr] == 0)
- break;
- fnSetInputFrameCount[wrapCntr](&pInfo->stream->bufferProcessor, size[wrapCntr]);
- for(i=0;i<pInfo->stream->userInputChannels;i++)
- {
- /* Only read as many channels as the user wants */
- fnSetInputChannel[wrapCntr](&pInfo->stream->bufferProcessor,
- i,
- ((unsigned char*)(data[wrapCntr]))+(i*pInfo->stream->capture.bytesPerSample),
- pInfo->stream->deviceInputChannels);
- }
- }
- }
- else
- {
- /* We haven't consumed anything from the ring buffer... */
- inputFramesAvailable = 0;
- /* If we have full-duplex, this is at startup, so mark no-input! */
- if (pInfo->stream->userOutputChannels>0 && pInfo->stream->userInputChannels>0)
- {
- PA_HP_TRACE((pInfo->stream->hLog, "Input startup, marking no input."));
- PaUtil_SetNoInput(&pInfo->stream->bufferProcessor);
- }
- }
- if (processFullDuplex) /* full duplex */
- {
- /* Only call the EndBufferProcessing function when the total input frames == total output frames */
- const unsigned long totalInputFrameCount = pInfo->stream->bufferProcessor.hostInputFrameCount[0] + pInfo->stream->bufferProcessor.hostInputFrameCount[1];
- const unsigned long totalOutputFrameCount = pInfo->stream->bufferProcessor.hostOutputFrameCount[0] + pInfo->stream->bufferProcessor.hostOutputFrameCount[1];
- if(totalInputFrameCount == totalOutputFrameCount && totalOutputFrameCount != 0)
- {
- framesProcessed = PaUtil_EndBufferProcessing(&pInfo->stream->bufferProcessor, &pInfo->cbResult);
- }
- else
- {
- framesProcessed = 0;
- }
- }
- else
- {
- framesProcessed = PaUtil_EndBufferProcessing(&pInfo->stream->bufferProcessor, &pInfo->cbResult);
- }
- PA_HP_TRACE((pInfo->stream->hLog, "Frames processed: %u %s", framesProcessed, (pInfo->priming ? "(priming)":"")));
- if( doChannelCopy )
- {
- DATAPACKET* packet = pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet;
- /* Copy the first output channel to the other channels */
- switch (pInfo->stream->render.bytesPerSample)
- {
- case 2:
- DuplicateFirstChannelInt16(packet->Header.Data, pInfo->stream->deviceOutputChannels, pInfo->stream->render.framesPerBuffer);
- break;
- case 3:
- DuplicateFirstChannelInt24(packet->Header.Data, pInfo->stream->deviceOutputChannels, pInfo->stream->render.framesPerBuffer);
- break;
- case 4:
- DuplicateFirstChannelInt32(packet->Header.Data, pInfo->stream->deviceOutputChannels, pInfo->stream->render.framesPerBuffer);
- break;
- default:
- assert(0); /* Unsupported format! */
- break;
- }
- }
- PaUtil_EndCpuLoadMeasurement( &pInfo->stream->cpuLoadMeasurer, framesProcessed );
- if (inputFramesAvailable)
- {
- PaUtil_AdvanceRingBufferReadIndex(&pInfo->stream->ringBuffer, inputFramesAvailable);
- }
- if (pInfo->renderTail != pInfo->renderHead)
- {
- if (!pInfo->stream->streamStop)
- {
- result = pInfo->stream->render.pPin->fnSubmitHandler(pInfo, pInfo->renderTail);
- if (result != paNoError)
- {
- PA_HP_TRACE((pInfo->stream->hLog, "Capture submit handler failed with result %d", result));
- return result;
- }
- }
- pInfo->renderTail++;
- if (!pInfo->pinsStarted && pInfo->priming == 0)
- {
- /* We start the pins here to allow "prime time" */
- if ((result = StartPins(pInfo)) == paNoError)
- {
- PA_HP_TRACE((pInfo->stream->hLog, "Starting pins!"));
- pInfo->pinsStarted = 1;
- }
- }
- }
- }
- return result;
- }
- static VOID CALLBACK TimerAPCWaveRTPolledMode(
- LPVOID lpArgToCompletionRoutine,
- DWORD dwTimerLowValue,
- DWORD dwTimerHighValue)
- {
- HANDLE* pHandles = (HANDLE*)lpArgToCompletionRoutine;
- if (pHandles[0]) SetEvent(pHandles[0]);
- if (pHandles[1]) SetEvent(pHandles[1]);
- }
- static DWORD GetCurrentTimeInMillisecs()
- {
- return timeGetTime();
- }
- PA_THREAD_FUNC ProcessingThread(void* pParam)
- {
- PaError result = paNoError;
- HANDLE hAVRT = NULL;
- HANDLE hTimer = NULL;
- HANDLE *handleArray = NULL;
- HANDLE timerEventHandles[2] = {0};
- unsigned noOfHandles = 0;
- unsigned captureEvents = 0;
- unsigned renderEvents = 0;
- unsigned timerPeriod = 0;
- DWORD timeStamp[2] = {0};
- PaProcessThreadInfo info;
- memset(&info, 0, sizeof(PaProcessThreadInfo));
- info.stream = (PaWinWdmStream*)pParam;
- info.stream->threadResult = paNoError;
- PA_LOGE_;
- info.ti.inputBufferAdcTime = 0.0;
- info.ti.currentTime = 0.0;
- info.ti.outputBufferDacTime = 0.0;
- PA_DEBUG(("In buffer len: %.3f ms\n",(2000*info.stream->capture.framesPerBuffer) / info.stream->streamRepresentation.streamInfo.sampleRate));
- PA_DEBUG(("Out buffer len: %.3f ms\n",(2000*info.stream->render.framesPerBuffer) / info.stream->streamRepresentation.streamInfo.sampleRate));
- info.timeout = (DWORD)max(
- (2000*info.stream->render.framesPerBuffer/info.stream->streamRepresentation.streamInfo.sampleRate + 0.5),
- (2000*info.stream->capture.framesPerBuffer/info.stream->streamRepresentation.streamInfo.sampleRate + 0.5));
- info.timeout = max(info.timeout*8, 100);
- timerPeriod = info.timeout;
- PA_DEBUG(("Timeout = %ld ms\n",info.timeout));
- /* Allocate handle array */
- handleArray = (HANDLE*)PaUtil_AllocateMemory((info.stream->capture.noOfPackets + info.stream->render.noOfPackets + 1) * sizeof(HANDLE));
- /* Setup handle array for WFMO */
- if (info.stream->capture.pPin != 0)
- {
- handleArray[noOfHandles++] = info.stream->capture.events[0];
- if (info.stream->capture.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic)
- {
- unsigned i;
- for(i=1; i < info.stream->capture.noOfPackets; ++i)
- {
- handleArray[noOfHandles++] = info.stream->capture.events[i];
- }
- }
- captureEvents = noOfHandles;
- renderEvents = noOfHandles;
- }
- if (info.stream->render.pPin != 0)
- {
- handleArray[noOfHandles++] = info.stream->render.events[0];
- if (info.stream->render.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic)
- {
- unsigned i;
- for(i=1; i < info.stream->render.noOfPackets; ++i)
- {
- handleArray[noOfHandles++] = info.stream->render.events[i];
- }
- }
- renderEvents = noOfHandles;
- }
- handleArray[noOfHandles++] = info.stream->eventAbort;
- assert(noOfHandles <= (info.stream->capture.noOfPackets + info.stream->render.noOfPackets + 1));
- /* Prepare render and capture pins */
- if ((result = PreparePinsForStart(&info)) != paNoError)
- {
- PA_DEBUG(("Failed to prepare device(s)!\n"));
- goto error;
- }
- /* Init high speed logger */
- if (PaUtil_InitializeHighSpeedLog(&info.stream->hLog, 1000000) != paNoError)
- {
- PA_DEBUG(("Failed to init high speed logger!\n"));
- goto error;
- }
- /* Heighten priority here */
- hAVRT = BumpThreadPriority();
- /* If input only, we start the pins immediately */
- if (info.stream->render.pPin == 0)
- {
- if ((result = StartPins(&info)) != paNoError)
- {
- PA_DEBUG(("Failed to start device(s)!\n"));
- goto error;
- }
- info.pinsStarted = 1;
- }
- /* Handle WaveRT polled mode */
- {
- const unsigned fs = (unsigned)info.stream->streamRepresentation.streamInfo.sampleRate;
- if (info.stream->capture.pPin != 0 && info.stream->capture.pPin->pinKsSubType == SubType_kPolled)
- {
- timerEventHandles[0] = info.stream->capture.events[0];
- timerPeriod = min(timerPeriod, (1000*info.stream->capture.framesPerBuffer)/fs);
- }
- if (info.stream->render.pPin != 0 && info.stream->render.pPin->pinKsSubType == SubType_kPolled)
- {
- timerEventHandles[1] = info.stream->render.events[0];
- timerPeriod = min(timerPeriod, (1000*info.stream->render.framesPerBuffer)/fs);
- }
- if (timerEventHandles[0] || timerEventHandles[1])
- {
- LARGE_INTEGER dueTime = {0};
- timerPeriod=max(timerPeriod/5,1);
- PA_DEBUG(("Timer event handles=0x%04X,0x%04X period=%u ms", timerEventHandles[0], timerEventHandles[1], timerPeriod));
- hTimer = CreateWaitableTimer(0, FALSE, NULL);
- if (hTimer == NULL)
- {
- result = paUnanticipatedHostError;
- goto error;
- }
- /* invoke first timeout immediately */
- if (!SetWaitableTimer(hTimer, &dueTime, timerPeriod, TimerAPCWaveRTPolledMode, timerEventHandles, FALSE))
- {
- result = paUnanticipatedHostError;
- goto error;
- }
- PA_DEBUG(("Waitable timer started, period = %u ms\n", timerPeriod));
- }
- }
- /* Mark stream as active */
- info.stream->streamActive = 1;
- info.stream->threadResult = paNoError;
- /* Up and running... */
- SetEvent(info.stream->eventStreamStart[StreamStart_kOk]);
- /* Take timestamp here */
- timeStamp[0] = timeStamp[1] = GetCurrentTimeInMillisecs();
- while(!info.stream->streamAbort)
- {
- unsigned doProcessing = 1;
- unsigned wait = WaitForMultipleObjects(noOfHandles, handleArray, FALSE, 0);
- unsigned eventSignalled = wait - WAIT_OBJECT_0;
- DWORD dwCurrentTime = 0;
- if (wait == WAIT_FAILED)
- {
- PA_DEBUG(("Wait failed = %ld! \n",wait));
- break;
- }
- if (wait == WAIT_TIMEOUT)
- {
- wait = WaitForMultipleObjectsEx(noOfHandles, handleArray, FALSE, 50, TRUE);
- eventSignalled = wait - WAIT_OBJECT_0;
- }
- else
- {
- if (eventSignalled < captureEvents)
- {
- if (PaUtil_GetRingBufferWriteAvailable(&info.stream->ringBuffer) == 0)
- {
- PA_HP_TRACE((info.stream->hLog, "!!!!! Input overflow !!!!!"));
- info.underover |= paInputOverflow;
- }
- }
- else if (eventSignalled < renderEvents)
- {
- if (!info.priming && info.renderHead - info.renderTail > 1)
- {
- PA_HP_TRACE((info.stream->hLog, "!!!!! Output underflow !!!!!"));
- info.underover |= paOutputUnderflow;
- }
- }
- }
- /* Get event time */
- dwCurrentTime = GetCurrentTimeInMillisecs();
- /* Since we can mix capture/render devices between WaveCyclic, WaveRT polled and WaveRT notification (3x3 combinations),
- we can't rely on the timeout of WFMO to check for device timeouts, we need to keep tally. */
- if (info.stream->capture.pPin && (dwCurrentTime - timeStamp[0]) >= info.timeout)
- {
- PA_DEBUG(("Timeout for capture device (%u ms)!", info.timeout, (dwCurrentTime - timeStamp[0])));
- result = paTimedOut;
- break;
- }
- if (info.stream->render.pPin && (dwCurrentTime - timeStamp[1]) >= info.timeout)
- {
- PA_DEBUG(("Timeout for render device (%u ms)!", info.timeout, (dwCurrentTime - timeStamp[1])));
- result = paTimedOut;
- break;
- }
- if (wait == WAIT_IO_COMPLETION)
- {
- /* Waitable timer has fired! */
- PA_HP_TRACE((info.stream->hLog, "WAIT_IO_COMPLETION"));
- continue;
- }
- if (wait == WAIT_TIMEOUT)
- {
- continue;
- }
- else
- {
- if (eventSignalled < captureEvents)
- {
- if (info.stream->capture.pPin->fnEventHandler(&info, eventSignalled) == paNoError)
- {
- timeStamp[0] = dwCurrentTime;
- /* Since we use the ring buffer, we can submit the buffers directly */
- if (!info.stream->streamStop)
- {
- result = info.stream->capture.pPin->fnSubmitHandler(&info, info.captureTail);
- if (result != paNoError)
- {
- PA_HP_TRACE((info.stream->hLog, "Capture submit handler failed with result %d", result));
- break;
- }
- }
- ++info.captureTail;
- /* If full-duplex, let _only_ render event trigger processing. We still need the stream stop
- handling working, so let that be processed anyways... */
- if (info.stream->userOutputChannels > 0)
- {
- doProcessing = 0;
- }
- }
- }
- else if (eventSignalled < renderEvents)
- {
- timeStamp[1] = dwCurrentTime;
- eventSignalled -= captureEvents;
- info.stream->render.pPin->fnEventHandler(&info, eventSignalled);
- }
- else
- {
- assert(info.stream->streamAbort);
- PA_HP_TRACE((info.stream->hLog, "Stream abort!"));
- continue;
- }
- }
- /* Handle processing */
- if (doProcessing)
- {
- result = PaDoProcessing(&info);
- if (result != paNoError)
- {
- PA_HP_TRACE((info.stream->hLog, "PaDoProcessing failed!"));
- break;
- }
- }
- if(info.stream->streamStop && info.cbResult != paComplete)
- {
- PA_HP_TRACE((info.stream->hLog, "Stream stop! pending=%d",info.pending));
- info.cbResult = paComplete; /* Stop, but play remaining buffers */
- }
- if(info.pending<=0)
- {
- PA_HP_TRACE((info.stream->hLog, "pending==0 finished..."));
- break;
- }
- if((!info.stream->render.pPin)&&(info.cbResult!=paContinue))
- {
- PA_HP_TRACE((info.stream->hLog, "record only cbResult=%d...",info.cbResult));
- break;
- }
- }
- PA_DEBUG(("Finished processing loop\n"));
- info.stream->threadResult = result;
- goto bailout;
- error:
- PA_DEBUG(("Error starting processing thread\n"));
- /* Set the "error" event together with result */
- info.stream->threadResult = result;
- SetEvent(info.stream->eventStreamStart[StreamStart_kFailed]);
- bailout:
- if (hTimer)
- {
- PA_DEBUG(("Waitable timer stopped\n", timerPeriod));
- CancelWaitableTimer(hTimer);
- CloseHandle(hTimer);
- hTimer = 0;
- }
- if (info.pinsStarted)
- {
- StopPins(&info);
- }
- /* Lower prio here */
- DropThreadPriority(hAVRT);
- if (handleArray != NULL)
- {
- PaUtil_FreeMemory(handleArray);
- }
- #if PA_TRACE_REALTIME_EVENTS
- if (info.stream->hLog)
- {
- PA_DEBUG(("Dumping highspeed trace...\n"));
- PaUtil_DumpHighSpeedLog(info.stream->hLog, "hp_trace.log");
- PaUtil_DiscardHighSpeedLog(info.stream->hLog);
- info.stream->hLog = 0;
- }
- #endif
- info.stream->streamActive = 0;
- if((!info.stream->streamStop)&&(!info.stream->streamAbort))
- {
- /* Invoke the user stream finished callback */
- /* Only do it from here if not being stopped/aborted by user */
- if( info.stream->streamRepresentation.streamFinishedCallback != 0 )
- info.stream->streamRepresentation.streamFinishedCallback( info.stream->streamRepresentation.userData );
- }
- info.stream->streamStop = 0;
- info.stream->streamAbort = 0;
- PA_LOGL_;
- return 0;
- }
- static PaError StartStream( PaStream *s )
- {
- PaError result = paNoError;
- PaWinWdmStream *stream = (PaWinWdmStream*)s;
- PA_LOGE_;
- if (stream->streamThread != NULL)
- {
- return paStreamIsNotStopped;
- }
- stream->streamStop = 0;
- stream->streamAbort = 0;
- ResetStreamEvents(stream);
- PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
- stream->oldProcessPriority = GetPriorityClass(GetCurrentProcess());
- /* Uncomment the following line to enable dynamic boosting of the process
- * priority to real time for best low latency support
- * Disabled by default because RT processes can easily block the OS */
- /*ret = SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS);
- PA_DEBUG(("Class ret = %d;",ret));*/
- stream->streamThread = CREATE_THREAD_FUNCTION (NULL, 0, ProcessingThread, stream, CREATE_SUSPENDED, NULL);
- if(stream->streamThread == NULL)
- {
- result = paInsufficientMemory;
- goto end;
- }
- ResumeThread(stream->streamThread);
- switch (WaitForMultipleObjects(2, stream->eventStreamStart, FALSE, 5000))
- {
- case WAIT_OBJECT_0 + StreamStart_kOk:
- PA_DEBUG(("Processing thread started!\n"));
- result = paNoError;
- /* streamActive is set in processing thread */
- stream->streamStarted = 1;
- break;
- case WAIT_OBJECT_0 + StreamStart_kFailed:
- PA_DEBUG(("Processing thread start failed! (result=%d)\n", stream->threadResult));
- result = stream->threadResult;
- /* Wait for the stream to really exit */
- WaitForSingleObject(stream->streamThread, 200);
- CloseHandle(stream->streamThread);
- stream->streamThread = 0;
- break;
- case WAIT_TIMEOUT:
- default:
- result = paTimedOut;
- PaWinWDM_SetLastErrorInfo(result, "Failed to start processing thread (timeout)!");
- break;
- }
- end:
- PA_LOGL_;
- return result;
- }
- static PaError StopStream( PaStream *s )
- {
- PaError result = paNoError;
- PaWinWdmStream *stream = (PaWinWdmStream*)s;
- BOOL doCb = FALSE;
- PA_LOGE_;
- if(stream->streamActive)
- {
- DWORD dwExitCode;
- doCb = TRUE;
- stream->streamStop = 1;
- if (GetExitCodeThread(stream->streamThread, &dwExitCode) && dwExitCode == STILL_ACTIVE)
- {
- if (WaitForSingleObject(stream->streamThread, INFINITE) != WAIT_OBJECT_0)
- {
- PA_DEBUG(("StopStream: stream thread terminated\n"));
- TerminateThread(stream->streamThread, -1);
- result = paTimedOut;
- }
- }
- else
- {
- PA_DEBUG(("StopStream: GECT says not active, but streamActive is not false ??"));
- result = paUnanticipatedHostError;
- PaWinWDM_SetLastErrorInfo(result, "StopStream: GECT says not active, but streamActive = %d", stream->streamActive);
- }
- }
- else
- {
- if (stream->threadResult != paNoError)
- {
- PA_DEBUG(("StopStream: Stream not active (%d)\n", stream->threadResult));
- result = stream->threadResult;
- stream->threadResult = paNoError;
- }
- }
- if (stream->streamThread != NULL)
- {
- CloseHandle(stream->streamThread);
- stream->streamThread = 0;
- }
- stream->streamStarted = 0;
- stream->streamActive = 0;
- if(doCb)
- {
- /* Do user callback now after all state has been reset */
- /* This means it should be safe for the called function */
- /* to invoke e.g. StartStream */
- if( stream->streamRepresentation.streamFinishedCallback != 0 )
- stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
- }
- PA_LOGL_;
- return result;
- }
- static PaError AbortStream( PaStream *s )
- {
- PaError result = paNoError;
- PaWinWdmStream *stream = (PaWinWdmStream*)s;
- int doCb = 0;
- PA_LOGE_;
- if(stream->streamActive)
- {
- doCb = 1;
- stream->streamAbort = 1;
- SetEvent(stream->eventAbort); /* Signal immediately */
- if (WaitForSingleObject(stream->streamThread, 10000) != WAIT_OBJECT_0)
- {
- TerminateThread(stream->streamThread, -1);
- result = paTimedOut;
- PA_DEBUG(("AbortStream: stream thread terminated\n"));
- }
- assert(!stream->streamActive);
- }
- CloseHandle(stream->streamThread);
- stream->streamThread = NULL;
- stream->streamStarted = 0;
- if(doCb)
- {
- /* Do user callback now after all state has been reset */
- /* This means it should be safe for the called function */
- /* to invoke e.g. StartStream */
- if( stream->streamRepresentation.streamFinishedCallback != 0 )
- stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
- }
- stream->streamActive = 0;
- stream->streamStarted = 0;
- PA_LOGL_;
- return result;
- }
- static PaError IsStreamStopped( PaStream *s )
- {
- PaWinWdmStream *stream = (PaWinWdmStream*)s;
- int result = 0;
- PA_LOGE_;
- if(!stream->streamStarted)
- result = 1;
- PA_LOGL_;
- return result;
- }
- static PaError IsStreamActive( PaStream *s )
- {
- PaWinWdmStream *stream = (PaWinWdmStream*)s;
- int result = 0;
- PA_LOGE_;
- if(stream->streamActive)
- result = 1;
- PA_LOGL_;
- return result;
- }
- static PaTime GetStreamTime( PaStream* s )
- {
- PA_LOGE_;
- PA_LOGL_;
- (void)s;
- return PaUtil_GetTime();
- }
- static double GetStreamCpuLoad( PaStream* s )
- {
- PaWinWdmStream *stream = (PaWinWdmStream*)s;
- double result;
- PA_LOGE_;
- result = PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
- PA_LOGL_;
- return result;
- }
- /*
- As separate stream interfaces are used for blocking and callback
- streams, the following functions can be guaranteed to only be called
- for blocking streams.
- */
- static PaError ReadStream( PaStream* s,
- void *buffer,
- unsigned long frames )
- {
- PaWinWdmStream *stream = (PaWinWdmStream*)s;
- PA_LOGE_;
- /* suppress unused variable warnings */
- (void) buffer;
- (void) frames;
- (void) stream;
- /* IMPLEMENT ME, see portaudio.h for required behavior*/
- PA_LOGL_;
- return paInternalError;
- }
- static PaError WriteStream( PaStream* s,
- const void *buffer,
- unsigned long frames )
- {
- PaWinWdmStream *stream = (PaWinWdmStream*)s;
- PA_LOGE_;
- /* suppress unused variable warnings */
- (void) buffer;
- (void) frames;
- (void) stream;
- /* IMPLEMENT ME, see portaudio.h for required behavior*/
- PA_LOGL_;
- return paInternalError;
- }
- static signed long GetStreamReadAvailable( PaStream* s )
- {
- PaWinWdmStream *stream = (PaWinWdmStream*)s;
- PA_LOGE_;
- /* suppress unused variable warnings */
- (void) stream;
- /* IMPLEMENT ME, see portaudio.h for required behavior*/
- PA_LOGL_;
- return 0;
- }
- static signed long GetStreamWriteAvailable( PaStream* s )
- {
- PaWinWdmStream *stream = (PaWinWdmStream*)s;
- PA_LOGE_;
- /* suppress unused variable warnings */
- (void) stream;
- /* IMPLEMENT ME, see portaudio.h for required behavior*/
- PA_LOGL_;
- return 0;
- }
- /***************************************************************************************/
- /* Event and submit handlers for WaveCyclic */
- /***************************************************************************************/
- static PaError PaPinCaptureEventHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex)
- {
- PaError result = paNoError;
- ring_buffer_size_t frameCount;
- DATAPACKET* packet = pInfo->stream->capture.packets + eventIndex;
- assert( eventIndex < pInfo->stream->capture.noOfPackets );
- if (packet->Header.DataUsed == 0)
- {
- PA_HP_TRACE((pInfo->stream->hLog, ">>> Capture bogus event (no data): idx=%u", eventIndex));
- /* Bogus event, reset! This is to handle the behavior of this USB mic: http://shop.xtz.se/measurement-system/microphone-to-dirac-live-room-correction-suite
- on startup of streaming, where it erroneously sets the event without the corresponding buffer being filled (DataUsed == 0) */
- ResetEvent(packet->Signal.hEvent);
- result = -1; /* Only need this to be NOT paNoError */
- }
- else
- {
- pInfo->capturePackets[pInfo->captureHead & cPacketsArrayMask].packet = packet;
- frameCount = PaUtil_WriteRingBuffer(&pInfo->stream->ringBuffer, packet->Header.Data, pInfo->stream->capture.framesPerBuffer);
- PA_HP_TRACE((pInfo->stream->hLog, ">>> Capture event: idx=%u (frames=%u)", eventIndex, frameCount));
- ++pInfo->captureHead;
- }
- --pInfo->pending; /* This needs to be done in either case */
- return result;
- }
- static PaError PaPinCaptureSubmitHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex)
- {
- PaError result = paNoError;
- DATAPACKET* packet = pInfo->capturePackets[pInfo->captureTail & cPacketsArrayMask].packet;
- pInfo->capturePackets[pInfo->captureTail & cPacketsArrayMask].packet = 0;
- assert(packet != 0);
- PA_HP_TRACE((pInfo->stream->hLog, "Capture submit: %u", eventIndex));
- packet->Header.DataUsed = 0; /* Reset for reuse */
- ResetEvent(packet->Signal.hEvent);
- result = PinRead(pInfo->stream->capture.pPin->handle, packet);
- ++pInfo->pending;
- return result;
- }
- static PaError PaPinRenderEventHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex)
- {
- assert( eventIndex < pInfo->stream->render.noOfPackets );
- pInfo->renderPackets[pInfo->renderHead & cPacketsArrayMask].packet = pInfo->stream->render.packets + eventIndex;
- PA_HP_TRACE((pInfo->stream->hLog, "<<< Render event : idx=%u head=%u", eventIndex, pInfo->renderHead));
- ++pInfo->renderHead;
- --pInfo->pending;
- return paNoError;
- }
- static PaError PaPinRenderSubmitHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex)
- {
- PaError result = paNoError;
- DATAPACKET* packet = pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet;
- pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet = 0;
- assert(packet != 0);
- PA_HP_TRACE((pInfo->stream->hLog, "Render submit : %u idx=%u", pInfo->renderTail, (unsigned)(packet - pInfo->stream->render.packets)));
- ResetEvent(packet->Signal.hEvent);
- result = PinWrite(pInfo->stream->render.pPin->handle, packet);
- /* Reset event, just in case we have an analogous situation to capture (see PaPinCaptureSubmitHandler_WaveCyclic) */
- ++pInfo->pending;
- if (pInfo->priming)
- {
- --pInfo->priming;
- }
- return result;
- }
- /***************************************************************************************/
- /* Event and submit handlers for WaveRT */
- /***************************************************************************************/
- static PaError PaPinCaptureEventHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex)
- {
- unsigned long pos;
- unsigned realInBuf;
- unsigned frameCount;
- PaWinWdmIOInfo* pCapture = &pInfo->stream->capture;
- const unsigned halfInputBuffer = pCapture->hostBufferSize >> 1;
- PaWinWdmPin* pin = pCapture->pPin;
- DATAPACKET* packet = 0;
- /* Get hold of current ADC position */
- pin->fnAudioPosition(pin, &pos);
- /* Wrap it (robi: why not use hw latency compensation here ?? because pos then gets _way_ off from
- where it should be, i.e. at beginning or half buffer position. Why? No idea.) */
- pos %= pCapture->hostBufferSize;
- /* Then realInBuf will point to "other" half of double buffer */
- realInBuf = pos < halfInputBuffer ? 1U : 0U;
- packet = pInfo->stream->capture.packets + realInBuf;
- /* Call barrier (or dummy) */
- pin->fnMemBarrier();
- /* Put it in queue */
- frameCount = PaUtil_WriteRingBuffer(&pInfo->stream->ringBuffer, packet->Header.Data, pCapture->framesPerBuffer);
- pInfo->capturePackets[pInfo->captureHead & cPacketsArrayMask].packet = packet;
- PA_HP_TRACE((pInfo->stream->hLog, "Capture event (WaveRT): idx=%u head=%u (pos = %4.1lf%%, frames=%u)", realInBuf, pInfo->captureHead, (pos * 100.0 / pCapture->hostBufferSize), frameCount));
- ++pInfo->captureHead;
- --pInfo->pending;
- return paNoError;
- }
- static PaError PaPinCaptureEventHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex)
- {
- unsigned long pos;
- unsigned bytesToRead;
- PaWinWdmIOInfo* pCapture = &pInfo->stream->capture;
- const unsigned halfInputBuffer = pCapture->hostBufferSize>>1;
- PaWinWdmPin* pin = pInfo->stream->capture.pPin;
- /* Get hold of current ADC position */
- pin->fnAudioPosition(pin, &pos);
- /* Wrap it (robi: why not use hw latency compensation here ?? because pos then gets _way_ off from
- where it should be, i.e. at beginning or half buffer position. Why? No idea.) */
- /* Compensate for HW FIFO to get to last read buffer position */
- pos += pin->hwLatency;
- pos %= pCapture->hostBufferSize;
- /* Need to align position on frame boundary */
- pos &= ~(pCapture->bytesPerFrame - 1);
- /* Call barrier (or dummy) */
- pin->fnMemBarrier();
- /* Put it in "queue" */
- bytesToRead = (pCapture->hostBufferSize + pos - pCapture->lastPosition) % pCapture->hostBufferSize;
- if (bytesToRead > 0)
- {
- unsigned frameCount = PaUtil_WriteRingBuffer(&pInfo->stream->ringBuffer,
- pCapture->hostBuffer + pCapture->lastPosition,
- bytesToRead / pCapture->bytesPerFrame);
- pCapture->lastPosition = (pCapture->lastPosition + frameCount * pCapture->bytesPerFrame) % pCapture->hostBufferSize;
- PA_HP_TRACE((pInfo->stream->hLog, "Capture event (WaveRTPolled): pos = %4.1lf%%, framesRead=%u", (pos * 100.0 / pCapture->hostBufferSize), frameCount));
- ++pInfo->captureHead;
- --pInfo->pending;
- }
- return paNoError;
- }
- static PaError PaPinCaptureSubmitHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex)
- {
- pInfo->capturePackets[pInfo->captureTail & cPacketsArrayMask].packet = 0;
- ++pInfo->pending;
- return paNoError;
- }
- static PaError PaPinCaptureSubmitHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex)
- {
- pInfo->capturePackets[pInfo->captureTail & cPacketsArrayMask].packet = 0;
- ++pInfo->pending;
- return paNoError;
- }
- static PaError PaPinRenderEventHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex)
- {
- unsigned long pos;
- unsigned realOutBuf;
- PaWinWdmIOInfo* pRender = &pInfo->stream->render;
- const unsigned halfOutputBuffer = pRender->hostBufferSize >> 1;
- PaWinWdmPin* pin = pInfo->stream->render.pPin;
- PaIOPacket* ioPacket = &pInfo->renderPackets[pInfo->renderHead & cPacketsArrayMask];
- /* Get hold of current DAC position */
- pin->fnAudioPosition(pin, &pos);
- /* Compensate for HW FIFO to get to last read buffer position */
- pos += pin->hwLatency;
- /* Wrap it */
- pos %= pRender->hostBufferSize;
- /* And align it, not sure its really needed though */
- pos &= ~(pRender->bytesPerFrame - 1);
- /* Then realOutBuf will point to "other" half of double buffer */
- realOutBuf = pos < halfOutputBuffer ? 1U : 0U;
- if (pInfo->priming)
- {
- realOutBuf = pInfo->renderHead & 0x1;
- }
- ioPacket->packet = pInfo->stream->render.packets + realOutBuf;
- ioPacket->startByte = realOutBuf * halfOutputBuffer;
- ioPacket->lengthBytes = halfOutputBuffer;
- PA_HP_TRACE((pInfo->stream->hLog, "Render event (WaveRT) : idx=%u head=%u (pos = %4.1lf%%)", realOutBuf, pInfo->renderHead, (pos * 100.0 / pRender->hostBufferSize) ));
- ++pInfo->renderHead;
- --pInfo->pending;
- return paNoError;
- }
- static PaError PaPinRenderEventHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex)
- {
- unsigned long pos;
- unsigned realOutBuf;
- unsigned bytesToWrite;
- PaWinWdmIOInfo* pRender = &pInfo->stream->render;
- const unsigned halfOutputBuffer = pRender->hostBufferSize >> 1;
- PaWinWdmPin* pin = pInfo->stream->render.pPin;
- PaIOPacket* ioPacket = &pInfo->renderPackets[pInfo->renderHead & cPacketsArrayMask];
- /* Get hold of current DAC position */
- pin->fnAudioPosition(pin, &pos);
- /* Compensate for HW FIFO to get to last read buffer position */
- pos += pin->hwLatency;
- /* Wrap it */
- pos %= pRender->hostBufferSize;
- /* And align it, not sure its really needed though */
- pos &= ~(pRender->bytesPerFrame - 1);
- if (pInfo->priming)
- {
- realOutBuf = pInfo->renderHead & 0x1;
- ioPacket->packet = pInfo->stream->render.packets + realOutBuf;
- ioPacket->startByte = realOutBuf * halfOutputBuffer;
- ioPacket->lengthBytes = halfOutputBuffer;
- ++pInfo->renderHead;
- --pInfo->pending;
- }
- else
- {
- bytesToWrite = (pRender->hostBufferSize + pos - pRender->lastPosition) % pRender->hostBufferSize;
- ++pRender->pollCntr;
- if (bytesToWrite >= halfOutputBuffer)
- {
- realOutBuf = (pos < halfOutputBuffer) ? 1U : 0U;
- ioPacket->packet = pInfo->stream->render.packets + realOutBuf;
- pRender->lastPosition = realOutBuf ? 0U : halfOutputBuffer;
- ioPacket->startByte = realOutBuf * halfOutputBuffer;
- ioPacket->lengthBytes = halfOutputBuffer;
- ++pInfo->renderHead;
- --pInfo->pending;
- PA_HP_TRACE((pInfo->stream->hLog, "Render event (WaveRTPolled) : idx=%u head=%u (pos = %4.1lf%%, cnt=%u)", realOutBuf, pInfo->renderHead, (pos * 100.0 / pRender->hostBufferSize), pRender->pollCntr));
- pRender->pollCntr = 0;
- }
- }
- return paNoError;
- }
- static PaError PaPinRenderSubmitHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex)
- {
- PaWinWdmPin* pin = pInfo->stream->render.pPin;
- pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet = 0;
- /* Call barrier (if needed) */
- pin->fnMemBarrier();
- PA_HP_TRACE((pInfo->stream->hLog, "Render submit (WaveRT) : submit=%u", pInfo->renderTail));
- ++pInfo->pending;
- if (pInfo->priming)
- {
- --pInfo->priming;
- if (pInfo->priming)
- {
- PA_HP_TRACE((pInfo->stream->hLog, "Setting WaveRT event for priming (2)"));
- SetEvent(pInfo->stream->render.events[0]);
- }
- }
- return paNoError;
- }
- static PaError PaPinRenderSubmitHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex)
- {
- PaWinWdmPin* pin = pInfo->stream->render.pPin;
- pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet = 0;
- /* Call barrier (if needed) */
- pin->fnMemBarrier();
- PA_HP_TRACE((pInfo->stream->hLog, "Render submit (WaveRTPolled) : submit=%u", pInfo->renderTail));
- ++pInfo->pending;
- if (pInfo->priming)
- {
- --pInfo->priming;
- if (pInfo->priming)
- {
- PA_HP_TRACE((pInfo->stream->hLog, "Setting WaveRT event for priming (2)"));
- SetEvent(pInfo->stream->render.events[0]);
- }
- }
- return paNoError;
- }
|