[C++] Audio playback realtime

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • LauPro
  • Registratie: Augustus 2001
  • Laatst online: 19-09 16:51

LauPro

Prof Mierenneuke®

Topicstarter
Ik heb een project waarbij ik twee 'kanalen' heb:
• audio afspeel (voornamelijk ADPCM44.1) dit speel ik af op OSX en Linux.
• aansturing van apparatuur gebaseerd op muziek.

Waar ik echter steeds tegenaan loop is dat de library die ik voor de playback gebruik hickups geeft of niet neer synchroom loopt, de volgende libraries heb ik getest:
• SDL
• QT 4.8.1's QAudioOutput

Hierbij gebruik ik momenteel QT als laatste. Wat ik sowieso merk aan de QAudioOutput is dat deze niet echt stabiel is. Waar het aan ligt is mij nog onduidelijk. Het probleem is dat datgene dat ik doe perfect op de muziek gelijk moet lopen. Bij SDL heb ik geen feedback over hoe ver de player is in de stream. Daar moet ik dus een aparte 'metronoom' mee laten lopen. Bij elke hickup tussen deze twee processen ontstaat er dan dus een verschil.

Bij QT is er de functie setNotifyInterval(). Echter komt het random voor dat midden in een file die ik aan het afspelen zijn ik geen feedback meer krijg van de QAudioOutput. Op dat moment stopt dus de aansturing van de apparatuur. Waarom ik geen feedback meer krijg is mij een raadsel, het schijnt volgens QT Mailing lists met QT 5.0 een stuk beter te moeten werken.

Dat biedt mij nu geen oplossing dus ik ben aan het kijken of ik niet meer lowlevel die audioaansturing kan gaan doen. Zodat de routine die de playback doet ook de aansturing van de apparatuur kan triggeren.

Om toch een beetje crossplatform te blijven zit ik dan te denken aan PulseAudio met libsndfile. In principe zit ik dan in de sf_read_double()-loop die iets zou kunnen triggeren.

Deze sf_read_double()-loop zou ik dan in een aparte thread willen stoppen en ik zou graag om de 50 of 100ms een update willen hebben. Afhankelijk van de buffergrootte zou ik dit moeten kunnen berekenen.

Om delays te voorkomen zou ik het liefst de hele wave-file in het geheugen zetten. Ik denk dat dit namelijk een van de redenen van de hickups is. libsndfile heeft een mooie sf_open_virtual() functie.

Wat zie ik nog meer over het hoofd om deze player backend helemaal smooth te krijgen? Ik gebruik pthreads en kan dan SCHED_FIFO gebruiken om deze thread de hoogste prioriteit te geven.

Inkoopacties - HENK terug! - Megabit
It is a war here, so be a general!


Acties:
  • 0 Henk 'm!

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

Een hele WAV inladen kan nogal lang duren (file I/O etc). Je kan ook on-the-fly laden danwel decoderen om je geheugengebruik acceptabel te houden. Als je alleen een desktop machine met GB+ RAM gebruikt, kan je wellicht met hele WAV's wegkomen, maar dat is niet echt "normaal".

Op het meest low-level is het meestal zo dat je een buffer maakt voor je device (die moet matchen met de configuratie (ie, juiste frequentie en datatype en aantal channels). Soms is dat makkelijk (als je device je audioformaat direct ondersteund) of moeilijker (vereist transformatie). Buffers zijn vaak in de orde-grootte van honderden milliseconden.

Als programmeur draag JIJ de verantwoordelijkheid om de juiste buffers op tijd aan te maken en aan te geven, en nadat je device klaar is met een buffer, die weer op te ruimen danwel te hergebruiken. Vaak is het mogelijk om dmv een callback informatie te ontvangen over wanneer een buffer "klaar" is met spelen, dus adhv die informatie zou je je andere aansturing kunnen synchroniseren.

Al met al word het al snel complex als je meerdere audio-formaten wilt decoderen en bufferen, mogelijk mixen en domein omzettingen (fourier transforms) voor effecten wilt doen, maar ik ga je niet tegenhouden :)

[ Voor 10% gewijzigd door MLM op 02-10-2012 14:24 ]

-niks-


Acties:
  • 0 Henk 'm!

  • LauPro
  • Registratie: Augustus 2001
  • Laatst online: 19-09 16:51

LauPro

Prof Mierenneuke®

Topicstarter
Het systeem heeft 2 GB geheugen, waar na de boot nog 1880 MB vrij is. Er is dus principe genoeg ruimte beschikbaar voor geheugen. De WAV in dit geval is tussen de 50 en 100 MB. Er zit toevallig een snelle HDD in van 127 MB/sec. Het laden van enkele seconden is acceptabel.

Juist om dat complexe met buffers te vermijden dacht ik dat het handiger is om alles in het het geheugen te zetten en dan door die buffer heen te lopen.

Het uitlezen van het audioformaat heb ik al een WAVE-file parser voor. Dus die kan ik inzetten op basis van deze gegevens.

Mixen en effecten zijn niet nodig en ga ik mij zeker niet aan wagen. Maar ik merk op dat er geen lekkere crossplatform lib is die alles kan (decoden en API voor hardware) behalve dan bijvoorbeeld Qt en ffmeg. Echter is de API van ffmeg ook weer zo complex dat ik het niet echt vertrouw.

Misschien kan ik nog beter VLC als backend gebruiken...

Inkoopacties - HENK terug! - Megabit
It is a war here, so be a general!


Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 16:28
LauPro schreef op dinsdag 02 oktober 2012 @ 14:05:
Bij SDL heb ik geen feedback over hoe ver de player is in de stream.
Bedoel je SDL of SDL_mixer? In beiden ontbreekt deze functionaliteit inderdaad, maar met SDL_mixer kun je tenminste nog een postmix handler installeren zodat je met een granulariteit van één buffer kunt bijhouden waar je ongeveer bent (wat geloof ik ook de granulariteit is die je via Qt krijgt nu?)

Het klopt wel dat SDL_mixer relatief beperkte functionaliteit heeft, dus als je ingewikkelde dingen wil doen zul je waarschijnlijk zelf moeten mixen. Maar in de TS beschrijf jij eigenlijk niets wat je met SDL_mixer niet al kan, dus dan maak je het jezelf met een low-level API vooral ingewikkelder.

Acties:
  • 0 Henk 'm!

  • remco_k
  • Registratie: April 2002
  • Laatst online: 15:38

remco_k

een cassettebandje was genoeg

LauPro schreef op dinsdag 02 oktober 2012 @ 15:05:
Het systeem heeft 2 GB geheugen, waar na de boot nog 1880 MB vrij is. Er is dus principe genoeg ruimte beschikbaar voor geheugen. De WAV in dit geval is tussen de 50 en 100 MB. Er zit toevallig een snelle HDD in van 127 MB/sec. Het laden van enkele seconden is acceptabel.
Toch denk ik dat je je daar niet aan moet wagen*.
Lees gewoon hooguit een seconde of 5 tot 10 vooruit in de file, dus 5 tot 10 seconden in geheugen.
Verder geen verstand van ontwikkeling onder Linux libs (ik ben een Windows man), maar het is allemaal uiteindelijk hetzelfde. Je maakt een buffer, kopieert daar de samples in en geeft 'm aan de driver. Die gebruikt hem als hij er aan toe is, en daarna krijg jij hem terug voor of hergebruik of om te destroyen.
Wave is de simpelste vorm om mee te testen. Dat hoeft je niet te decoderen. Als je de wave data chunk hebt, kun je vanaf dat punt 1 op 1 de data doorzetten naar je geluidskaart tot het einde van die chunk, onder de voorwaarde dat de geluidskaart natuurlijk dat betreffende formaat ondersteund (zeg b.v.: 44.1 kHz/16bits/2ch).

Als dat al niet hikloos af kan spelen, lijkt mij dat er iets fundamenteel mis is met het systeem, of met je code.
In die zin snap ik je idee om de wave even helemaal in het gebeugen te hebben, om even uit te proberen, maar ook als de wave op schijf staat moet dat in een dergelijk systeem met gemak zonder problemen spelen.

* Waarom niet in het geheugen?
Stel je hebt straks een wave file met audio van een uur. Grootte is c.a. 640MB oid.
Dat past best in gebeugen waar nog 1880MB vrij is. Zou je denken.
Maar, er bestaat ook nog zoiets als geheugen fragmentatie (Bij Windows machines dan, en ik denk dat dat bij Linux niet anders is).
Verschillende applicaties gebruiken verschillende geheugenblokjes verspreid over het hele geheugen. Vooral naarmate de uptime groter wordt.
Hierdoor kán je potentieel hebben dat die wave file niet in één blok van 640MB in het geheugen past.... En dan? ---> Out of memory error. :)

[ Voor 16% gewijzigd door remco_k op 02-10-2012 16:35 ]

Alles kan stuk.


Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 16:28
remco_k schreef op dinsdag 02 oktober 2012 @ 16:27:
Maar, er bestaat ook nog zoiets als geheugen fragmentatie (Bij Windows machines dan, en ik denk dat dat bij Linux niet anders is).
Het is niet zozeer het geheugen dat gefragmenteerd raakt maar de virtual memory space. Dit probleem treedt praktisch gezien alleen op onder 32-bits systemen, aangezien 64-bits systemen een geheugenbus hebben van minimaal 48 bits ofzo, wat betekent dat fragmentatie eigenlijk geen issue is als je minder dan honderd terabyte geheugen gebruikt. ;)

Acties:
  • 0 Henk 'm!

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Misschien is OpenAL nog een optie om wat meer low-level met hardware buffers en events te kunnen werken.

Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 16:28
Ik heb nooit echt begrepen wat de concrete voordelen van OpenAL t.o.v. SDL zijn? Ik snap dat OpenAL support heeft voor 3D effecten, maar als je die niet nodig hebt, blijven er dan nog voordelen over?

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

Soultaker schreef op dinsdag 02 oktober 2012 @ 16:56:
[...]

Het is niet zozeer het geheugen dat gefragmenteerd raakt maar de virtual memory space. Dit probleem treedt praktisch gezien alleen op onder 32-bits systemen, aangezien 64-bits systemen een geheugenbus hebben van minimaal 48 bits ofzo, wat betekent dat fragmentatie eigenlijk geen issue is als je minder dan honderd terabyte geheugen gebruikt. ;)
Tenzij de audio hardware vereist dat het fysieke geheugen contiguous gealloceerd wordt.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 16:28
Ik ging uit van een systeem waarbij de audio data weliswaar in het geheugen wordt gedecodeerd maar alsnog naar de audio buffer wordt gekopieerd wanneer die leeg raakt; v.z.i.w. werken de meeste sound systems ook zo, al is het alleen maar om software mixing te implementeren.

(In theorie is dat natuurlijk minder efficiënt dan de hardware bestaande buffers laten mixen, maar goed, audio processing is meestal niet het meest cpu-belastende deel van je applicatie).



Op zich wel een interessante (maar enigzins off-topic) vraag: kun je überhaupt in user-mode allocaties doen die op contiguous physical memory gemapt worden? Onder Linux heb ik dat nog nooit gedaan en v.z.i.w. is er geen mmap() parameter waarmee je dat zou kunnen afdwingen, en hoewel je een allocatie wel in memory kan locken, garandeert dat niet dat je ook contiguous memory krijgt.

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

In Windows kan het iig niet, maar dat soort dingen doe je dan meestal via de betreffende driver. Ook voor grafische resources bijvoorbeeld.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

In Windows KAN het volgens mij wel met AllocateUserPhysicalPages, die zijn typisch wel contiguous (ook al is dat niet gegarandeerd). Maar goed, dan moet je process draaien met oa SeLockMemoryPrivilege, dat is ook niet een feestje.

De enige manier om echt gegarandeerd contiguous physical memory te krijgen in Windows, moet je volgens mij in kernel-mode zijn, maar dat is echt een beetje offtopic :)

De systemen waarmee ik bekend ben die daadwerkelijk van de programmeur verwachten dat ze contiguous physical memory regelen, zijn echt ERG low-level (sommige consoles) of specifiek (hardware drivers). Daarnaast zijn er ook nog systemen waarbij virtual memory niet eens van toepassing is omdat je typisch toch maar 1 applicatie draait (games op handhelds).

Anyways, om terug te komen op topic, als je wel met buffer-granulariteit kan bepalen waar in de stream je zit, kan je ook gewoon kleinere buffers gebruiken om de granulariteit te verbeteren :P

-niks-


Acties:
  • 0 Henk 'm!

  • BoAC
  • Registratie: Februari 2003
  • Laatst online: 20-09 23:24

BoAC

Memento mori

Ik heb soortgelijke problemen gehad bij gebruik van output via SOX en pipes. Ik ben daarna overgestapt naar JACK audio omdat die bijna realtime is qua latency.

Acties:
  • 0 Henk 'm!

  • LauPro
  • Registratie: Augustus 2001
  • Laatst online: 19-09 16:51

LauPro

Prof Mierenneuke®

Topicstarter
Soultaker schreef op dinsdag 02 oktober 2012 @ 16:20:
Het klopt wel dat SDL_mixer relatief beperkte functionaliteit heeft, dus als je ingewikkelde dingen wil doen zul je waarschijnlijk zelf moeten mixen. Maar in de TS beschrijf jij eigenlijk niets wat je met SDL_mixer niet al kan, dus dan maak je het jezelf met een low-level API vooral ingewikkelder.
Inderdaad SDL_mixer. Deze heb ik gebruikt maar ik had het gevoel dat ik totaal geen controle had over wanneer ik de stream instart. In het programma moet het zo zijn dat als ik zeg GO, dat hij dan ook direct start met afspelen niet enkele honderden miliseconden later.
remco_k schreef op dinsdag 02 oktober 2012 @ 16:27:
Toch denk ik dat je je daar niet aan moet wagen*.
Lees gewoon hooguit een seconde of 5 tot 10 vooruit in de file, dus 5 tot 10 seconden in geheugen.
Verder geen verstand van ontwikkeling onder Linux libs (ik ben een Windows man), maar het is allemaal uiteindelijk hetzelfde. Je maakt een buffer, kopieert daar de samples in en geeft 'm aan de driver. Die gebruikt hem als hij er aan toe is, en daarna krijg jij hem terug voor of hergebruik of om te destroyen.
Wave is de simpelste vorm om mee te testen. Dat hoeft je niet te decoderen. Als je de wave data chunk hebt, kun je vanaf dat punt 1 op 1 de data doorzetten naar je geluidskaart tot het einde van die chunk, onder de voorwaarde dat de geluidskaart natuurlijk dat betreffende formaat ondersteund (zeg b.v.: 44.1 kHz/16bits/2ch).
Ik snap helemaal dat geheel inladen deze functionaliteit limiteert. Echter is het product an sich gelimiteerd en ik ben overeengekomen met de opdrachtgever dat de muziek nooit langer dan 10 minuten duurt, dus dan is een nummer van een uur een 'feature'. Al hoewel ik het ermee eens ben dat het technisch geen mooie oplossing is maar het gaat nu even om wat praktisch werkt.
Als dat al niet hikloos af kan spelen, lijkt mij dat er iets fundamenteel mis is met het systeem, of met je code.
In die zin snap ik je idee om de wave even helemaal in het gebeugen te hebben, om even uit te proberen, maar ook als de wave op schijf staat moet dat in een dergelijk systeem met gemak zonder problemen spelen.
Het stomme is dat ik met de QAudioDevice niets anders doe dan een stream starten en laten loopen. En dan op een gegeven moment dan loopt alles in de soep. Terwijl ik bij elke 'loop' netjes terug seek naar het begin van de file en ik heb eigenlijk elke stap al talloze keren getest. Ik vind het ook een beetje raar dat die API van QT niet zelf een aantal zaken af vangt, omdat ze dit dus niet doen wil ik eigenlijk gewoon 100% controle hebben over de audio en niet moeten vertrouwen op een tussenlaag.

Dank voor de adviezen tot nog toe.

Inkoopacties - HENK terug! - Megabit
It is a war here, so be a general!


Acties:
  • 0 Henk 'm!

  • EddoH
  • Registratie: Maart 2009
  • Niet online

EddoH

Backpfeifengesicht

Beschrijf eerst eens precies wat het probleem is en hoe je je systeem hebt opgezet.
Ik begrijp dat je een audio stream wilt afspelen en tegelijkertijd acties naar een apparaat wilt sturen op basis van de afgespeelde muziek.

Wat bedoel je precies met 'hickup'? Het klinkt mij in de oren alsof je af en toe last heb van een buffer underrun tijdens het streamen van je data naar de audio playback buffers. Hoe doe je dit precies? Als jij op het moment dat je een notificatie krijgt om nieuw data aan te leveren in een file gaat zitten seeken kan ik je garanderen dat dat een keer mis moet gaan. Je data moet al klaar staan op het moment dat gevraagd wordt om het aan te leveren. Doe je dit niet dan starve je de buffers en moet je audio hw recoveren op het moment dat je weer nieuwe data aanlevert-> gevolg, een hickup in je audio.

Gebruik je een aparte thread om te streamen? Hoe implementeer je deze? Gebruik je toevallig sleep calls in die thread?
Probeer eerst de audio streaming betrouwbaar te krijgen voordat je ook maar begint aan synchroniseren van je apparaat aansturen met de audio stream.

Acties:
  • 0 Henk 'm!

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

Je hebt ten alle tijden tenminste 2 buffers nodig, omdat je device er altijd 1 afspeelt, en een 2e om tegelijkertijd op te vullen en klaar te zetten (voordat de 1e "op" is).
Je kan prima zodra als je een callback krijgt met "deze buffer is klaar" diezelfde buffer vullen met de volgende data en direct klaar zetten voor gebruik. Als je op dat punt nog file I/O moet gaan doen, ben je wellicht te laat :) Je kan eventueel meer buffers gebruiken voor stabielere aanvoer (opvangen van "langzame" buffers in de tijd dat andere buffers lopen), maar dat gaat wel ten koste van latency op effecten etc.

Maar gezien de situatie van de TS waar hij alles al in RAM heeft staan, zou je het prima simpel kunnen aanpakken met 2 buffers :)

-niks-


Acties:
  • 0 Henk 'm!

  • LauPro
  • Registratie: Augustus 2001
  • Laatst online: 19-09 16:51

LauPro

Prof Mierenneuke®

Topicstarter
Het is eigenlijk heel simpel: ik open een QFile en ga daar in zitten seeken. Ik laat het dan aan de QFile om die buffers te vullen, dit ook op basis van de programmeervoorbeelden van QT. Maar ik begrijp nu (en op zich volkomen logisch) dat het hebben van een QFile alleen niet genoeg is, ik zal een buffermechanisme er tussen moeten zetten. Dus inderdaad denk ik dat de QFile nu de bottleneck is.

In de huidige situatie loopt de QAudioDevice welke de muziek speelt in een aparte thread. Hij stuurt dan dmv queued signals notificaties tussen twee threads over hoe ver hij in de stream is.

In de nieuwe situatie wil ik QT niet meer gaan gebruiken voor het afspelen van audio maar wil ik werken met twee buffers van 10 MB. Bij normaal gebruik zal dan de harde schijf kunnen slapen. Is de muziek meer dan 10 MB dan leest hij het tweede deel in etc.

Inkoopacties - HENK terug! - Megabit
It is a war here, so be a general!


Acties:
  • 0 Henk 'm!

  • EddoH
  • Registratie: Maart 2009
  • Niet online

EddoH

Backpfeifengesicht

MLM schreef op woensdag 03 oktober 2012 @ 11:26:
Je hebt ten alle tijden tenminste 2 buffers nodig, omdat je device er altijd 1 afspeelt, en een 2e om tegelijkertijd op te vullen en klaar te zetten (voordat de 1e "op" is).
Je kan prima zodra als je een callback krijgt met "deze buffer is klaar" diezelfde buffer vullen met de volgende data en direct klaar zetten voor gebruik. Als je op dat punt nog file I/O moet gaan doen, ben je wellicht te laat :) Je kan eventueel meer buffers gebruiken voor stabielere aanvoer (opvangen van "langzame" buffers in de tijd dat andere buffers lopen), maar dat gaat wel ten koste van latency op effecten etc.

Maar gezien de situatie van de TS waar hij alles al in RAM heeft staan, zou je het prima simpel kunnen aanpakken met 2 buffers :)
Dit. Met de opmerking dat de buffer waaruit wordt afgespeeld zich al in de hw en/of audio drivers bevind. het volstaat om 1 buffer te hebben in je applicatie waaruit je direct data kan aanleveren aan de audio interface.

Edit: Deze applicatie buffer moet je echter niet pas gaan vullen vanuit de file als er om data gevraagd wordt.

[ Voor 5% gewijzigd door EddoH op 03-10-2012 11:51 ]


Acties:
  • 0 Henk 'm!

  • Adion
  • Registratie: Januari 2001
  • Laatst online: 15:35
Voor een platform-onafhankelijke library kan je wellicht naar BASS kijken.
Dan moet je je niet meer zelf bezighouden met het decoden, bufferen en op de juiste tijd aan de geluids-api buffers aanleveren.

VirtualDJ 2024 - Fast Image Resizer - Instagram


Acties:
  • 0 Henk 'm!

  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

LauPro schreef op woensdag 03 oktober 2012 @ 11:40:
Het is eigenlijk heel simpel: ik open een QFile en ga daar in zitten seeken. Ik laat het dan aan de QFile om die buffers te vullen, dit ook op basis van de programmeervoorbeelden van QT. Maar ik begrijp nu (en op zich volkomen logisch) dat het hebben van een QFile alleen niet genoeg is, ik zal een buffermechanisme er tussen moeten zetten. Dus inderdaad denk ik dat de QFile nu de bottleneck is.

In de huidige situatie loopt de QAudioDevice welke de muziek speelt in een aparte thread. Hij stuurt dan dmv queued signals notificaties tussen twee threads over hoe ver hij in de stream is.

In de nieuwe situatie wil ik QT niet meer gaan gebruiken voor het afspelen van audio maar wil ik werken met twee buffers van 10 MB. Bij normaal gebruik zal dan de harde schijf kunnen slapen. Is de muziek meer dan 10 MB dan leest hij het tweede deel in etc.
Threading is wel het minste wat je moet doen... Let er bovendien op dat je niet zonder omkijken SCHED_FIFO neemt met maxiumum prioriteit. Er bestaat ook nog zoiets als kernel threads; Je kan lelijke priority inversion krijgen als je je prioriteiten slecht kiest.

Daarnaast:
- Een en ander hangt af van je audio driver, audio subsystem en audio library. Er bestaan zat artikels over skip-free audio op Linux en wat je allemaal moet doen om er te raken. Hierboven werd JACK al aangeraden; er zijn ook wat kernel tweaks (in /proc wsch) die je kunt doen.
- Wat file IO betreft kun je hints aan de kernel geven (fadvise(...FADV_SEQUENTIAL...)). Hangt af van je kernel versie, natuurlijk...
- Mogelijk heb je er wat aan om de RT preemption patches te gebruiken op je kernel, afhankelijk van hoe ver je wil gaan...

Ik heb geen ervaring met audio playback op Linux, maar van wat ik me herinner van Windows heb je een serie buffers die je opvult en doorgeeft. Daarna krijg je die buffer terug als hij uitgespeeld is.
Door veel relatief kleine buffers te gebruiken (bvb 10*100K) kun je wel een en ander doen om te bepalen waar je zit in de playback.

Op de vraag of je contiguous memory kunt alloceren onder Linux:
hangt af van je kernel versie. Vanaf 3.5 (afaik) is er de Contiguous Memory Allocator. Deze is natuurlijk bedoeld om in de kernel te gebruiken. In userspace is die mogelijkheid er niet, tenzij de driver het contiguous memory mapt in userspace. Typische gebruikers hiervan zijn media drivers (camera's bvb) die aaneensluitende blokken fysisch geheugen nodig hebben omdat ze geen scatter/gather ondersteunen. Aangezien die buffers naar userspace doorgegeven moeten worden, kan de driver die mappen, zodat userspace de data kan uitlezen.

ASSUME makes an ASS out of U and ME


Acties:
  • 0 Henk 'm!

  • EddoH
  • Registratie: Maart 2009
  • Niet online

EddoH

Backpfeifengesicht

Allemaal leuke tips natuurlijk, maar als je voor het streamen van audio op een powerhouse als een desktop pc je toevlucht gaat zoeken in realtime kernel patches en contiguous memory, dan ben je gewoon helemaal verkeerd bezig.
Daarnaast zijn meer dan 2 buffers natuurlijk niet nodig (10*100K buffers ??). En is een period size van 100k (uiteraard afhankelijk van je audioformaat) veel te groot als je precies wilt weten waar je in de stream aan het afspelen bent.

Je moet zorgen dat je threading en buffer model klopt als een bus en weten waar je mee bezig bent. Dan maakt het platform/framework waar je de audio hw mee benaderd niet zoveel meer uit.

Acties:
  • 0 Henk 'm!

  • LauPro
  • Registratie: Augustus 2001
  • Laatst online: 19-09 16:51

LauPro

Prof Mierenneuke®

Topicstarter
Adion schreef op woensdag 03 oktober 2012 @ 19:11:
Voor een platform-onafhankelijke library kan je wellicht naar BASS kijken.
Dan moet je je niet meer zelf bezighouden met het decoden, bufferen en op de juiste tijd aan de geluids-api buffers aanleveren.
Erg leuke lib, in een library laten ze zich wel in met GTK wat mij wat af schrikt, ik wil daar ver uit de buurt blijven. Maar op zich zijn de features om de speakers te kunnen configureren wel mooi meegenomen. Ik ga er even mee testen!

@H!GHGuY: Threading is al het geval en niet echt de issue. Gezien de snelheid van de computer (Intel(R) Atom(TM) CPU D425 @ 1.80GHz). Ik hoef echt geen honderden MB's aan geheugen te alloceren :P .

Sowieso is het eigenlijk best wel onzinnig om die mp3 in het geheugen te zetten omdat de Linux filesystem caches dit al voor hun rekening nemen. Maar het is meer om het uit te sluiten. Op dit moment ben ik een implementatie aan het maken geheel buiten de GUI om, om ook deze factor uit te sluiten (ondanks dat het afspelen in een aparte thread draait).

Inkoopacties - HENK terug! - Megabit
It is a war here, so be a general!


Acties:
  • 0 Henk 'm!

  • bobo1on1
  • Registratie: Juli 2001
  • Laatst online: 18-05 17:57
Zelf maak ik gebruik van portaudio, dat is een cross platform lib die met vrij veel audio api's kan werken.

Impedance, a measure of opposition to time-varying electric current in an electric circuit.
Not to be confused with impotence.


Acties:
  • 0 Henk 'm!

  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

EddoH schreef op donderdag 04 oktober 2012 @ 16:06:
Allemaal leuke tips natuurlijk, maar als je voor het streamen van audio op een powerhouse als een desktop pc je toevlucht gaat zoeken in realtime kernel patches en contiguous memory, dan ben je gewoon helemaal verkeerd bezig.
Linux' default soft real-time gedrag is zonder PREEMPT_RT patches, redelijk te noemen. Er zijn echter al jarenlang 'klachten' uit de audio- en desktopwereld dat hun audio regelmatig skipt als er zaken als disk access bezig zijn.

Op dit punt kunnen de RT patches helpen. Contiguous memory is enkel nodig als de H/W niet overweg kan met scatter/gather DMA. Jammer genoeg is er van dat soort meer dan genoeg te vinden.
Daarnaast zijn meer dan 2 buffers natuurlijk niet nodig (10*100K buffers ??). En is een period size van 100k (uiteraard afhankelijk van je audioformaat) veel te groot als je precies wilt weten waar je in de stream aan het afspelen bent.
Meer dan 2 buffers geeft je:
- langere totale buffertijd (dus kleinere kans dat een high-latency disk access voor problemen zorgt)
- accuratere feedback waar je in je playback zit (als je enkel afgaat op wanneer je een buffer terug krijgt van je audio lib) Als de audiolibrary zelf nauwkeuriger kan aangeven waar hij bezig is, dan is dit niet zo'n probleem en kom je met 2 grote buffers ook toe.
Je moet zorgen dat je threading en buffer model klopt als een bus en weten waar je mee bezig bent. Dan maakt het platform/framework waar je de audio hw mee benaderd niet zoveel meer uit.
Helaas, je vergeet dat er ook componenten zijn waar je niets of weinig aan kan wijzigen (gegeven beperkte tijd en kennis). Je mag je buffer model nog op orde hebben, als je audio H/W driver er vervolgens niets van bakt heb je nog steeds een brak resultaat.
LauPro schreef op donderdag 04 oktober 2012 @ 21:50:
@H!GHGuY: Threading is al het geval en niet echt de issue. Gezien de snelheid van de computer (Intel(R) Atom(TM) CPU D425 @ 1.80GHz). Ik hoef echt geen honderden MB's aan geheugen te alloceren :P .
Over honderden MBs heb ik het niet... maar het kan geen kwaad om voldoende buffer aan te leggen en om de nodige hints aan de kernel te geven hoe je je files gaat accessen. Je wil niet dat je logrotate daemon zijn ding doet en plots je audio playback om zeep helpt...
Je zou trouwens ook kunnen kijken naar de keuze van je I/O scheduler...
Sowieso is het eigenlijk best wel onzinnig om die mp3 in het geheugen te zetten omdat de Linux filesystem caches dit al voor hun rekening nemen.
De disk cache neemt helemaal niets voor zijn rekening als jij die file voor de eerste keer leest. Er kan hoogstens wat readahead gedaan worden (standaard dacht ik dat dit rond de 128KB was). Als je daarenboven aangeeft dat je sequential access doet, kan de kernel sneller reeds gelezen data uit de disk cache halen en de volgende data alvast in de disk cache duwen.

De kernel moet qua performance meestal een trade-off maken tussen verschillende use-cases en vertrouwen op hints van userspace om dat ietsje meer uit je systeem te halen.

ASSUME makes an ASS out of U and ME


Acties:
  • 0 Henk 'm!

  • EddoH
  • Registratie: Maart 2009
  • Niet online

EddoH

Backpfeifengesicht

H!GHGuY schreef op vrijdag 05 oktober 2012 @ 12:44:
[...]

Linux' default soft real-time gedrag is zonder PREEMPT_RT patches, redelijk te noemen. Er zijn echter al jarenlang 'klachten' uit de audio- en desktopwereld dat hun audio regelmatig skipt als er zaken als disk access bezig zijn.

Op dit punt kunnen de RT patches helpen. Contiguous memory is enkel nodig als de H/W niet overweg kan met scatter/gather DMA. Jammer genoeg is er van dat soort meer dan genoeg te vinden.
Hij wil platform onafhankelijk software maken. Dan heb je geen boodschap aan speciale kernel patches die de scheduling van je OS veranderen. De PREEMPT_RT patches kunnen helpen om je buffersize te verkleinen zodat je audio latency omlaag kan tijdens realtime processing van je signal, dat klopt. Maar dat is hier niet aan de orde, het gaat erom dat hij buffer underruns krijgt bij het afspelen van een simpele audio stream.
Meer dan 2 buffers geeft je:
- langere totale buffertijd (dus kleinere kans dat een high-latency disk access voor problemen zorgt)
- accuratere feedback waar je in je playback zit (als je enkel afgaat op wanneer je een buffer terug krijgt van je audio lib) Als de audiolibrary zelf nauwkeuriger kan aangeven waar hij bezig is, dan is dit niet zo'n probleem en kom je met 2 grote buffers ook toe.
De gemiddel audio lib geeft geen buffers 'terug' maar vraagt je op een gegeven moment zijn buffer te vullen. Of je nu 2 of 10 buffers hebt maakt hier niet uit, je moet zorgen dat je een buffer hebt waaruit je direct audio kan aanleveren. Daarnaast is een buffer van 100k abnormaal groot in een gemiddeld streaming systeem en is deze buffersize veel te groot om aan te geven waar je in je stream zit. Realistische waardes zitten < 1k.
Helaas, je vergeet dat er ook componenten zijn waar je niets of weinig aan kan wijzigen (gegeven beperkte tijd en kennis). Je mag je buffer model nog op orde hebben, als je audio H/W driver er vervolgens niets van bakt heb je nog steeds een brak resultaat.
Klopt, daarom ontwerp je een systeem die zo goed mogelijk met verschillende hw en drivers om kan gaan. Als je een underrun krijgt vergroot je dynamisch je buffer. Output delay meet je eerst met een loopback voordat je je buffers initaliseerd. In/output synchronisatie doe je met add-dropper mechanismes. Een brakke driver fix je niet met je applicatie maar een audio stream afspelen moet zonder
problemen en zonder rigoreuze kernel scheduler aanpassen gewoon kunnen. En als je platform onafhankelijk wilt blijven blijf je er gewoon zo ver mogelijk vandaan. We hebben het hier niet over realtime signal processing van 4 streams die met een latency van <1 ms afgespeeld moeten worden...

Acties:
  • 0 Henk 'm!

  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

EddoH schreef op vrijdag 05 oktober 2012 @ 14:08:
[...]
Hij wil platform onafhankelijk software maken.
Die was ik even uit het oog verloren. Dan heb je inderdaad niets aan RT patches.
[...]
De gemiddel audio lib geeft geen buffers 'terug' maar vraagt je op een gegeven moment zijn buffer te vullen. Of je nu 2 of 10 buffers hebt maakt hier niet uit, je moet zorgen dat je een buffer hebt waaruit je direct audio kan aanleveren. Daarnaast is een buffer van 100k abnormaal groot in een gemiddeld streaming systeem en is deze buffersize veel te groot om aan te geven waar je in je stream zit. Realistische waardes zitten < 1k.
Teruggeven, vragen om buffer te vullen... potáto, potàto. Het is inherent hetzelfde.
Wat buffersize betreft, fair enough 100k is groot, ik had de moeite niet genomen om iets te gaan berekenen.
Maar ik zou alsnog opteren om veel buffers aan je audio lib te geven. Anders heb je 3 lagen buffering (I/O readahead, eigen buffering, audio lib buffering) waar je er zelf een van schrijft. Dat is er dus 1 teveel.
Daarenboven maak je de buffers in je audio lib voldoende groot, zodat een latency spike niet in een underrun resulteert.
A rato dat je buffers terugkrijgt (om te vullen dus ;) ) weet je ook dat deze net klaar is met afspelen en dat je audio lib in de daaropvolgende buffer is begonnen. Geen idee of dit nauwkeurig genoeg is voor de TS zijn applicatie, dat kan hij dan wel inschatten of uitzoeken.
[...]
Klopt, daarom ontwerp je een systeem die zo goed mogelijk met verschillende hw en drivers om kan gaan. Als je een underrun krijgt vergroot je dynamisch je buffer. Output delay meet je eerst met een loopback voordat je je buffers initaliseerd. In/output synchronisatie doe je met add-dropper mechanismes. Een brakke driver fix je niet met je applicatie maar een audio stream afspelen moet zonder
problemen en zonder rigoreuze kernel scheduler aanpassen gewoon kunnen. En als je platform onafhankelijk wilt blijven blijf je er gewoon zo ver mogelijk vandaan. We hebben het hier niet over realtime signal processing van 4 streams die met een latency van <1 ms afgespeeld moeten worden...
Fair enough, dit lijken me nauwkeuriger approaches... Laat de TS dan maar de afweging nauwkeurigheid/development tijd maken.

ASSUME makes an ASS out of U and ME

Pagina: 1