Forum: Mikrocontroller und Digitale Elektronik USB Audio - Verarbeitung des Prebuffers


von Markus G. (usound)


Lesenswert?

Hallo zusammen,

ich werkle gerade an einer USB-zu-I2S-Brücke auf einem Atmel SAMD21. Die 
Audioausgabe an sich funktioniert auch schon ohne Probleme (mit UAC1).

Ich teste momentan mit einer einfachen asynchronen Übertragung, der 
Endpoint hat genau die benötigte Größe (48 Samples x 2 Kanäle x 24 Bit = 
288 Byte).
Mit einem Counter zähle ich die ausgegebenen Samples auf dem I2S. Habe 
ich nun zu wenig oder zu viele Samples im FIFO, mache ich eine einfache 
SRC indem ich einen Sample verwerfe oder einen kopiere.
Der FIFO ist seitens der Größe variabel zwischen 4 und 32 Frames 
Speichergröße. Die kleinste Größe ist natürlich seitens der Latenz am 
wünschenswertesten.
Das ist zunächst nur ein einfacher Testcase. Die Synchronisation 
funktioniert so im Grunde auch schon.

Ich stelle nun aber fest, dass es durch das Pre-buffering bei nicht 
kontinuierlichen Streams (Youtube-Videos, MP3s in iTunes etc.) nach 
einigen Videos oder MP3s (jedesmal wird bei einem neuen Video/File vom 
Windows-Treiber geprebuffered) zu einem Overflow/Underrun meines FIFOs 
kommt. Das äußert sich dann in einer stark verzerrten Wiedergabe. Im 
Schnitt ist das alle 8 bis 10 Lieder bei Buffersize = 4 Frames der Fall 
(die Wiedergabe wird gestartet, wenn der FIFO halb gefüllt ist, Schreib- 
und Lesezeiger haben also den maximalen Abstand).

Zu viele Daten können nicht gesendet werden, da die maxPacketSize des 
Endpoints nur die 48 Samples aufnehmen kann.
Nichts desto trotz verursacht das Prebuffering in Windows, dass der 
Lesezeiger im Vergleich zum Schreibzeiger meines FIFOs beginnt 
auseinander zu driften.
Wie kann das zu Stande kommen?

Kennt jemand das Problem und weiß ggf. wie man dem Beikommen kann?
Wie läuft der Prozess dieses Prebufferings in Windows ab? Was passiert 
auf Seiten der USB-Datenausgabe?
Jegliche Infos/Links/Stichwörter zum Prozess des Prebufferings in 
Windows würden mir aber auch schon helfen, mich seitens der Recherche zu 
dem Thema in die richtige Richtung zu orientieren.

Wäre super, wenn mir jemand einen Tipp geben könnte.

Beste Grüße,
Markus

: Bearbeitet durch User
von Thomas Z. (usbman)


Lesenswert?

Wenn ein neuer Stream startet oder stopt bekommst du jedes mal einen 
SetInterface(Alternate).
Im Handler für diesen Requests initialisierst du dann deine Counter und 
alles was sonst noch notwendig ist um deine Ausgabe betriebsbereit zu 
machen.
Ich gehe davon aus, dass du noch keine SetSampleRate() implementiert 
hast. Das wäre der eigentliche Platz für den InitCode.
Was und wie Windows das macht ist eine Blackbox. Wenn's dich 
interessiert kannst du aber im DDK nachsehen Stichwort dort Audio 
Minidriver bzw AC97 Sample. Das ist aber sehr harte Kost.
Usbaudio baut für KS Audio einen Graph zusammen der die Features deiner 
Descriptoren abbildet. Es gibt auch ein Tool im DDK graphview oder so.

Thomas

von Markus G. (usound)


Lesenswert?

Thomas Z. schrieb:
> Wenn ein neuer Stream startet oder stoppt bekommst du jedes mal
> einen SetInterface(Alternate).
> Im Handler für diesen Requests initialisierst du dann deine Counter und
> alles was sonst noch notwendig ist um deine Ausgabe betriebsbereit zu
> machen.

Hallo Thomas,
genau so mache ich das auch. Wenn das alternate setting des Interface 
gesetzt wird, initialisiere ich alle benötigten Instanzen und Variablen 
neu. Die Ausgabe funktioniert auch, ebenso wie das Neustarten nach einem 
Stopp.

Dort liegt aber auch gar nicht das Problem. Angenommen ich stoppe die 
Audioausgabe (drücke in der Wiedergabe-Applikation auf Stopp), dann 
bleibt das Interface zunächst ca. 15 Sekunden im Abspielmodus. Auf dem 
USB werden dann lediglich Samples mit Nullen gesendet!

Ist ein Lied oder Video zu Ende, so wird das alt_setting garnicht 
zurückgesetzt. Am Anfang des neuen Lieds/Videos wird aber wieder 
zunächst der Pre-buffer gefüllt.
Zumindest glaube ich, dass dies der Ursprung des Problems ist, da der 
Buffer Over/Underflow bzw. die Verzerrungen immer am Anfang eines neuen 
Lieds/Videos auftreten.
Da muss folglich noch irgendwas anderes passieren.

> Ich gehe davon aus, dass du noch keine SetSampleRate() implementiert
> hast. Das wäre der eigentliche Platz für den InitCode.
Nein habe ich momentan noch nicht implementiert, ich arbeite mit einer 
fixen Samplerate von 48 kHz. Es steht auch nur diese im Descriptor.

> Was und wie Windows das macht ist eine Blackbox. Wenn's dich
> interessiert kannst du aber im DDK nachsehen Stichwort dort Audio
> Minidriver bzw AC97 Sample. Das ist aber sehr harte Kost.
Wenn sich das umgehen ließe, würde ich mir das natürlich gerne ersparen. 
Die Umstände, die das Problem verursachen kann ich momentan aber nicht 
anderweitig greifen, deswegen dachte ich, dass es womöglich sinnvoll 
ist, sich mit der Thematik tiefergehend zu beschäftigen.

Gruß
Markus

von Thomas Z. (usbman)


Lesenswert?

Markus G. schrieb:
> Angenommen ich stoppe die Audioausgabe (drücke in der
> Wiedergabe-Applikation auf Stopp), dann bleibt das Interface zunächst
> ca. 15 Sekunden im Abspielmodus. Auf dem USB werden dann lediglich
> Samples mit Nullen gesendet!

mm das ist seltsam. Ich habe zwar keine Erfahrung mit W10 aber bei allen 
anderen Windows Versionen kommt bei einem Stop ein SetInterface() mit 
einem Alternate==0. Das das Interface noch 15sec offen bleibt hab ich 
noch nie gesehen.
Bitte prüfe das mal mit usbview. Dieses Verhalten kenn ich nicht und hab 
ich auch noch nie gesehen. Wenn möglich benutze das Original usbview aus 
dem DDK. Das ist zwar buggy ohne Ende aber zeigt offene EPs sehr schnell 
an.
Ich vermute ein Bug bei deinem SetInterface().
Auch die 15sec ergeben für mich keinen Sinn. ksaudio hat meiner 
Erfahrung nach nur eine Latenz von etwa 10..50 ms.

Thomas

von Thomas Z. (usbman)


Angehängte Dateien:

Lesenswert?

ich hab mal das original usbview aus dem w7 ddk angehängt. Das ist 
vermutlich aber noch das gleiche wie das aus dem w98 ddk.

Noch eine Idee zu deinen 15 sec:
Das dürfte ein Timeout sein weil der SetInterface() request nicht 
korrekt ist. Ein USB Request besteht aus SetupStage, DataStage, und 
AckStage.
DataStage ist in diesem Fall 0 (wLength == 0). Dein Handler muss alles 
abschliesen bevor das NAK weggenommen wird und mit ACK der request 
bestätigt wird. Ich hoffe deine Lib macht das korrekt.
Ich schreib das deshalb weil ich schon zuviel USB code gesehen habe der 
das nicht korekt macht.

Thomas

von Markus G. (usound)


Lesenswert?

Thomas Z. schrieb:
> mm das ist seltsam. Ich habe zwar keine Erfahrung mit W10 aber bei allen
> anderen Windows Versionen kommt bei einem Stop ein SetInterface() mit
> einem Alternate==0. Das das Interface noch 15sec offen bleibt hab ich
> noch nie gesehen.

USB-View habe ich bereits für die Überprüfung der Enumeration verwendet.
Das Alternate setting des Interface habe ich zusätzlich auf eine LED 
geführt. Ich sehe also, sobald das alt_setting von 1 auf 0 geht.

Ich habe den Sachverhalt gerade mit Wireshark geprüft. Sowohl meine 
Implementierung, als auch eine USB-Soundkarte von Roland legen das 
gleiche Verhalten an den Tag!
Das alt_setting bleibt ca. 15-20 s auf 1 (aktiv), solange kommen auf dem 
USB Samples mit Nullen. Dann kommt ein set Interface und das alt_setting 
wird auf 0 gesetzt.

Rein aus einer logischen Überlegung heraus würde es doch auch keinen 
Sinn machen, dass das alt_setting sofort bei jeder Unterbrechung des 
Streams (anderes Video anklicken / nächstes Lied in der Abspielfolge 
eines MediaPlayers) zurückgesetzt wird. Das wäre ja unnötiger 
Bustransfer ohne Ende.

Gruß
Markus

von Markus G. (usound)


Lesenswert?

Thomas Z. schrieb:
> Noch eine Idee zu deinen 15 sec: Dein Handler muss alles
> abschliesen bevor das NAK weggenommen wird und mit ACK der request
> bestätigt wird. Ich hoffe deine Lib macht das korrekt.
> Ich schreib das deshalb weil ich schon zuviel USB code gesehen habe der
> das nicht korekt macht.

Hier der Log von Wireshark des Set Interface Requests:

Host -> Device:

Frame 4397: 36 bytes on wire (288 bits), 36 bytes captured (288 bits) on 
interface 0
USB URB
    [Source: host]
    [Destination: 2.18.0]
    USBPcap pseudoheader length: 28
    IRP ID: 0xffff960152c918a0
    IRP USBD_STATUS: USBD_STATUS_SUCCESS (0x00000000)
    URB Function: URB_FUNCTION_SELECT_INTERFACE (0x0001)
    IRP information: 0x00, Direction: FDO -> PDO
    URB bus id: 2
    Device address: 18
    Endpoint: 0x80, Direction: IN
    URB transfer type: URB_CONTROL (0x02)
    Packet Data Length: 8
    [Response in: 4398]
    Control transfer stage: Setup (0)
URB setup
    bmRequestType: 0x00
    bRequest: SET INTERFACE (11)
    bAlternateSetting: 0
    wInterface: 1
    wLength: 0

Device -> Host:

Frame 4398: 28 bytes on wire (224 bits), 28 bytes captured (224 bits) on 
interface 0
USB URB
    [Source: 2.18.0]
    [Destination: host]
    USBPcap pseudoheader length: 28
    IRP ID: 0xffff960152c918a0
    IRP USBD_STATUS: USBD_STATUS_SUCCESS (0x00000000)
    URB Function: URB_FUNCTION_SELECT_INTERFACE (0x0001)
    IRP information: 0x01, Direction: PDO -> FDO
    URB bus id: 2
    Device address: 18
    Endpoint: 0x80, Direction: IN
    URB transfer type: URB_CONTROL (0x02)
    Packet Data Length: 0
    [Request in: 4397]
    [Time from request: 0.000960000 seconds]
    Control transfer stage: Status (2)

Das sieht meinem Dafürhalten nach auf den ersten Blick in Ordnung aus. 
Bei der vorhandenen USB-Soundkarte sieht es genau identisch aus.
Ich vermute an der Verarbeitung des Requests kann es somit nicht liegen.

Gruß
Markus

von Markus G. (usound)


Lesenswert?

Thomas Z. schrieb:
> Markus G. schrieb:
>> Angenommen ich stoppe die Audioausgabe (drücke in der
>> Wiedergabe-Applikation auf Stopp), dann bleibt das Interface zunächst
>> ca. 15 Sekunden im Abspielmodus. Auf dem USB werden dann lediglich
>> Samples mit Nullen gesendet!
>
> mm das ist seltsam. Ich habe zwar keine Erfahrung mit W10 aber bei allen
> anderen Windows Versionen kommt bei einem Stop ein SetInterface() mit
> einem Alternate==0. Das das Interface noch 15sec offen bleibt hab ich
> noch nie gesehen.
> Bitte prüfe das mal mit usbview. Dieses Verhalten kenn ich nicht und hab
> ich auch noch nie gesehen. Wenn möglich benutze das Original usbview aus
> dem DDK. Das ist zwar buggy ohne Ende aber zeigt offene EPs sehr schnell
> an.
> Ich vermute ein Bug bei deinem SetInterface().
> Auch die 15sec ergeben für mich keinen Sinn. ksaudio hat meiner
> Erfahrung nach nur eine Latenz von etwa 10..50 ms.

Hallo,
habe das Thema nun nochmal etwas genauer unter die Lupe genommen.
Die Verwirrung entstand durch eine unpräzise Formulierung meinerseits. 
Ich habe meist mit Youtube-Videos oder in Itunes getestet. Dort habe ich 
in diesem Sinne nicht auf Stop gedrückt, sondern auf Pause!
Drückt man Pause, bleibt das Interface noch für ca. 18 Sekunden im 
Abspielmodus und wird dann erst abgeschaltet.
Drückt man Stop oder schließt den Tab im Browser oder wählt das nächste 
Lied, wird das Interface sofort in alt_setting = 0 gesetzt.

Das erklärt auch, warum ich beim Pausieren eines Streams keine Probleme 
mit dem Buffer auf meinem Device bekomme, da das Device diesen Umstand 
garnicht mitbekommt. Es kommen dann einfach nur 0-Samples.

Nun scheint es so zu sein, dass beim Wiederstart nach einem Stop Frames 
verloren gehen und somit meine Bufferindizes auseinander driften. Kann 
das sein?

Beste Grüße,
Markus

von Thomas Z. (usbman)


Lesenswert?

Ich würde einfach mal versuchen mit wireshark nach class requests zu 
suchen.
Ich vermute ja ganz stark dass dort SetSampleRate Requests auftauchen 
auch wenn du das bisher in den Descriptoren ausgeschlossen hast. Dann 
wäre es interessant ob du diese mit STALL bedienst. Beachte auch das 
SetSampleRate im Gegensatz zu den meisten anderen Requests ein Requests 
mit Datastage ist (wlength≠0) Manche Libs beherrschen das nicht.

Thomas

von Markus G. (usound)


Angehängte Dateien:

Lesenswert?

Thomas Z. schrieb:
> Ich würde einfach mal versuchen mit wireshark nach class requests
> zu
> suchen.
> Ich vermute ja ganz stark dass dort SetSampleRate Requests auftauchen
> auch wenn du das bisher in den Descriptoren ausgeschlossen hast. Dann
> wäre es interessant ob du diese mit STALL bedienst. Beachte auch das
> SetSampleRate im Gegensatz zu den meisten anderen Requests ein Requests
> mit Datastage ist (wlength≠0) Manche Libs beherrschen das nicht.
>
> Thomas

Hallo Thomas,

habe gerade nochmals mit Wireshark geprüft, was passiert wenn ich den 
Stream stoppe. Das verhält sich soweit wie erwartet, es kommt im Prinzip 
sofort ein SetInterface Request und das altSetting wird auf 0 gesetzt 
(siehe angehängtes Bild).

Gruß
Markus

von Thomas Z. (usbman)


Lesenswert?

Markus G. schrieb:
> habe gerade nochmals mit Wireshark geprüft, was passiert wenn ich den
> Stream stoppe. Das verhält sich soweit wie erwartet, es kommt im Prinzip
> sofort ein SetInterface Request und das altSetting wird auf 0 gesetzt
> (siehe angehängtes Bild).

Das war aber gar nicht die Frage. Wenn ich dich richtig verstehe 
bekommst du immer dann ein Problem wenn nach dem 2. SetAlternate(0) ein 
SetAlternate(1) kommt.
Der erste SetAlternate(0) kommt dabei während der Enumeration.
Vielleicht ist es einfach so dass du deinen EP beim SetInterface (1) 
nicht richtig einstellst und das beim ersten Streamstart nur zufällig 
richtig eingestellt ist.

Thomas

von Markus G. (usound)


Lesenswert?

Thomas Z. schrieb:
> Markus G. schrieb:
>> habe gerade nochmals mit Wireshark geprüft, was passiert wenn ich den
>> Stream stoppe. Das verhält sich soweit wie erwartet, es kommt im Prinzip
>> sofort ein SetInterface Request und das altSetting wird auf 0 gesetzt
>> (siehe angehängtes Bild).
>
> Das war aber gar nicht die Frage. Wenn ich dich richtig verstehe
> bekommst du immer dann ein Problem wenn nach dem 2. SetAlternate(0) ein
> SetAlternate(1) kommt.
> Der erste SetAlternate(0) kommt dabei während der Enumeration.
> Vielleicht ist es einfach so dass du deinen EP beim SetInterface (1)
> nicht richtig einstellst und das beim ersten Streamstart nur zufällig
> richtig eingestellt ist.
>
> Thomas

Hallo,

Um das Ganze nochmals etwas zu präzisieren:
Z.B. wenn ein Lied gewechselt wird oder das nächste Youtube-Video kommt, 
geht das Interface von 1 -> 0 und dann sobald die Daten vom neuen Video 
gebuffert sind, direkt wieder von 0 -> 1 (soweit die Theorie, siehe 
weiter unten).
Nach ca. 10-15 Mal, bekomme ich einen Buffer Over/Underrun auf meinem 
Device, was sich durch Verzerrungen bei der Wiedergabe äußert.

Beim Übergang 1 - 0 - 1 des altSettings scheint irgendwas zu passieren, 
das ich mir noch nicht so recht erklären kann.
Auf meinem Device zähle ich die gesendeten Samples auf dem I2S mit 
(immer im Start-of-Frame Interrupt des USB-Moduls wird dieser 
ausgewertet). Die eingehenden Daten via USB sind konstant auf 48 Samples 
pro Frame fixiert.

Damit meine Bufferpointer auseinander/aufeinander zu laufen, müsste 
folgendes passieren:
- es werden zu viel/zu wenig Daten über USB in einem Frame gesendet: 
diesen Fall habe ich mittels der EndpointSize und der Option 
MaxpacketsOnly ausgemerzt.
- es kommen ganze Datenframes nicht an
- es werden SOFs nicht erkannt

Habe nun noch Tests gemacht und so wie mir scheint das Problem noch 
etwas eingegrenzt.
Ich habe mir eine LED auf den SetInterface-Request gelegt. Diese ist an, 
wenn altSetting=1 und aus, wenn das altSetting zurückgesetzt wird.
Zudem habe ich eine LED die mit 20 Hz blinkt und im Data-received 
Interrupt des USBs verarbeitet wird. Diese hört also sofort auf, wenn 
der Datenstrom unterbrochen wird.

Nun beobachte ich drei verschiedene Sachen (geprüft mit Wireshark):
1. Ich teste in Audacity: ich lasse etwas abspielen und sobald ich auf 
Stopp drücke wird der Datenstrom unterbrochen und das Interface 
zurückgesetzt (sehr kleine Latenz).
Soweit wie erwartet.

2. Lasse ich nun ein Video abspielen und schließe das Browserfenster 
oder den Tab, dann wird zunächst der Datenstrom unterbrochen (mit etwas 
größerer Verzögerung als in Testfall 1, denke das ist aber durch die 
Vorverarbeitung/Buffering des Videos zu erklären).
Das Interface bleibt dann aber noch ca. 4 Sekunden aktiv und wird dann 
erst mit einem SetInterface zurückgesetzt!

3. Ich lasse ein Video abspielen und klicke dann im Betrieb ein anderes 
an.
Dabei kommt das Interface gar nicht dazu zurückgesetzt zu werden!
Hier liegt also vermutlich das Problem. Der Datenstrom reist ab, das 
Interface ist aber noch im Abspielmodus. Der Neustart des Datenstroms 
kommt dann so schnell, dass das Device von der zwischenzeitlichen 
Unterbrechung nichts mitbekommt. Entsprechend werden die Buffer und 
zugehörige Pointer nicht zurückgesetzt. Dadurch akkumuliert sich ein 
Offset bei jedem Auftreten.

Nun frage ich mich, ob das am Device liegen kann. Ansich ist das doch 
eine Treibersache auf der Hostseite. Das Device kann ja nur auf Aktionen 
reagieren, die übermittelt werden.

Kann es sein, dass man zwingend ein zusätzliches HID-Interface braucht, 
über das die Play/Pause/Stopp-Aktionen auf der Hostseite übertragen 
werden?
Ich vermute, dann wäre das Device immer im Bilde, was gerade auf dem 
Host passiert.
Bin für jeden Hinweis dankbar.

Gruß
Markus

: Bearbeitet durch User
von Thomas Z. (usbman)


Lesenswert?

Markus G. schrieb:
> Kann es sein, dass man zwingend ein zusätzliches HID-Interface braucht,
> über das die Play/Pause/Stopp-Aktionen auf der Hostseite übertragen
> werden?
> Ich vermute, dann wäre das Device immer im Bilde, was gerade auf dem
> Host passiert.

Nein HID ist nicht notwendig. Keines meiner Devices implementiert HID. 
Die funktionieren seit w98se problemlos. Kannst du mit wireshark 
irgendwelche anderen Requests zusätzlich zu SetInterface () erkennen? 
Versuch mal beim Setup eine Error Led einzuschalten die bei jedem 
unbekannten Requests angeht (ev Timeout gesteuert) 5ms reichen dann 
siehst du die jedesmal aufblitzen wenn ein Request auftaucht den dein 
Device nicht beherrscht.
Das kannst du dann verfeinern indem du das z.B. nur für std requests 
oder class requests machst. Ich hatte damals die Möglichkeit die CPU 
jederzeit anzuhalten da die Streams per DMA ausgegeben wurden.
Falls SOFs fehlen wird der Framecounter nicht stetig sein auch das kann 
man auslesen und auswerten.

Thomas

von Joe F. (easylife)


Lesenswert?

Markus G. schrieb:
> - es werden zu viel/zu wenig Daten über USB in einem Frame gesendet:
> diesen Fall habe ich mittels der EndpointSize und der Option
> MaxpacketsOnly ausgemerzt.

Damit hast du nichts "ausgemerzt" sondern schaffst dir Probleme.
Dein Endpoint muss in der Lage sein 49 Samples entgegenzunehmen, und 
auch 47.
Das ist ein ganz normaler Fall, auch wenn beide Clocks scheinbar gleich 
schnell sind. Genau gleich schnell sind sie eben nicht, und daher 
braucht man immer die Möglichkeit mal ein Sample mehr oder weniger 
übertragen zu können.
Mit deinem "Fix" schmeisst du regelmäßig gültige Datenpakete weg, und 
dein Buffer läuft langfristig zwangsläufig leer.
Eine zweite Fehlerquelle kann sein, dass nach einem Underrun (zB. durch 
einen gestoppten Stream) nicht gewartet wird, bis der FIFO wieder 
genügend voll ist.
Wenn das (pre-buffering nach underrun) nicht geschieht, läuft der FIFO 
ab diesem Moment in kurzen Abständen hörbar leer.

: Bearbeitet durch User
von Markus G. (usound)


Lesenswert?

Hallo zusammen,
danke für eure Anmerkungen.

Thomas Z. schrieb:
> Kannst du mit wireshark
> irgendwelche anderen Requests zusätzlich zu SetInterface () erkennen?
Soweit ich bisher gesehen habe nicht. Werde morgen früh aber nochmal 
genauer schauen.

> Versuch mal beim Setup eine Error Led einzuschalten die bei jedem
> unbekannten Requests angeht (ev Timeout gesteuert) 5ms reichen dann
> siehst du die jedesmal aufblitzen wenn ein Request auftaucht den dein
> Device nicht beherrscht.
> Das kannst du dann verfeinern indem du das z.B. nur für std requests
> oder class requests machst. Ich hatte damals die Möglichkeit die CPU
> jederzeit anzuhalten da die Streams per DMA ausgegeben wurden.
> Falls SOFs fehlen wird der Framecounter nicht stetig sein auch das kann
> man auslesen und auswerten.
Werde ich mir auch morgen anschauen, aber ansich brauche ich doch nach 
erfolgreicher Enumeration nur noch den SetInterface Request für die 
Audiofunktion oder?

Joe F. schrieb:
> Damit hast du nichts "ausgemerzt" sondern schaffst dir Probleme.
> Dein Endpoint muss in der Lage sein 49 Samples entgegenzunehmen, und
> auch 47.
> Das ist ein ganz normaler Fall, auch wenn beide Clocks scheinbar gleich
> schnell sind. Genau gleich schnell sind sie eben nicht, und daher
> braucht man immer die Möglichkeit mal ein Sample mehr oder weniger
> übertragen zu können.
> Mit deinem "Fix" schmeisst du regelmäßig gültige Datenpakete weg, und
> dein Buffer läuft langfristig zwangsläufig leer.
Der Endpoint läuft momentan einfach im synchronen Modus. Auf dem Device 
mache ich im Prinzip eine rudimentäre Sample Rate Conversion. Habe ich 
zu wenig Samples im FIFO, kopiere ich einen, habe ich zu viel, lösche 
ich einen.
Das funktioniert (bei kontinuierlichen Streams) soweit auch.
Den asynchronen Endpoint mit Feedback-Pfad wollte ich erst umsetzen, 
wenn die "Audio-Grundfunktion" korrekt läuft.
Oder brauche ich für den synchronen Endpoint auch die Möglichkeit 47 
bzw. 49 Samples zu übertragen?

> Eine zweite Fehlerquelle kann sein, dass nach einem Underrun (zB. durch
> einen gestoppten Stream) nicht gewartet wird, bis der FIFO wieder
> genügend voll ist.
> Wenn das (pre-buffering nach underrun) nicht geschieht, läuft der FIFO
> ab diesem Moment in kurzen Abständen hörbar leer.
Wenn der Stream gestoppt wird (altSetting geht auf 0), werden alle 
Buffer und Indizes zurückgesetzt. Beim Streamingbegin wird immer 
gewartet bis der Buffer halb voll ist, bis mit der Ausgabe per I2S 
begonnen wird.

Gruß
Markus

von Joe F. (easylife)


Lesenswert?

Markus G. schrieb:
> Der Endpoint läuft momentan einfach im synchronen Modus. Auf dem Device
> mache ich im Prinzip eine rudimentäre Sample Rate Conversion. Habe ich
> zu wenig Samples im FIFO, kopiere ich einen, habe ich zu viel, lösche
> ich einen.

Das heisst aber nicht, dass der Host immer genau 48 Samples pro Paket 
sendet.
Die Audio-Clock im Host kann durchaus von der USB-Clock abweichen.
In der Regel ist das zwar minimal, führt aber zu der Notwendigkeit ab 
und zu ein "Ausgleichspaket" zu übertragen. Da du in diesem Fall immer 
gleich das gesamte Paket nicht akzeptierst, läufst du recht schnell in 
einen Underrun.

> Das funktioniert (bei kontinuierlichen Streams) soweit auch.
> Den asynchronen Endpoint mit Feedback-Pfad wollte ich erst umsetzen,
> wenn die "Audio-Grundfunktion" korrekt läuft.
> Oder brauche ich für den synchronen Endpoint auch die Möglichkeit 47
> bzw. 49 Samples zu übertragen?

Ja. Das ist ja auch kein großes Problem. Mache den Endpoint etwas größer 
und fülle in den FIFO was vom Host ankommt.

: Bearbeitet durch User
von Markus G. (usound)


Lesenswert?

Joe F. schrieb:
> Die Audio-Clock im Host kann durchaus von der USB-Clock abweichen.
> In der Regel ist das zwar minimal, führt aber zu der Notwendigkeit ab
> und zu ein "Ausgleichspaket" zu übertragen. Da du in diesem Fall immer
> gleich das gesamte Paket nicht akzeptierst, läufst du recht schnell in
> einen Underrun.
> Ja. Das ist ja auch kein großes Problem. Mache den Endpoint etwas größer
> und fülle in den FIFO was vom Host ankommt.

Hallo,

habe nun die Endpointsize angepasst:
1
#define SPEAKER_NOM_SAMPLES_PER_SOF  ((uint16_t)(SYSTEM_SAMPLE_RATE/1000) * SPEAKER_NB_CHANNELS)
2
#define UDI_AUDIO_SPEAKER_EP_SIZE  ((SPEAKER_NOM_SAMPLES_PER_SOF + SPEAKER_NB_CHANNELS) * SPEAKER_SAMPLE_LEN)
Somit habe ich immer einen Sample pro Kanal mehr Platz im Endpoint (in 
meinem Fall nun 294 Byte).
Nebenfrage: Wie verhält sich das eigentlich bei nicht ganzzahligen 
Samplezahlen pro Frame?
Z.B. bei 44,1 kHz, ist da die Basisrate 44 kHz und ich brauche dann 
Platz für 45 Samples oder mehr?

Das war auf jeden Fall eine sinnvolle Korrektur für die 
Langzeitstabilität. Meine Problematik, die z.B. beim direkten Umschalten 
eines Videos auftritt, löst das aber auch nicht.
Das betrifft im Grunde nur den beschriebenen Spezialfall: Stream wird 
gestoppt, Interface aber nicht zurückgesetzt, Stream direkt wieder 
gestartet.
Sobald das Interface zurückgesetzt wird, kann kein Problem entstehen, da 
ich wieder einen sauber konsistenten Zustand meines FIFOs und der 
zugehörigen Variablen habe (alles auf Reset/Ausgangszustand beim Start).

Werde nochmals versuchen etwas genauer zu lokalisieren wo das Problem 
entsteht. Nochmals zur Frage von oben:
Brauche ich nach erfolgreicher Enumeration nur noch den SetInterface 
Request für die Audiofunktion oder noch andere (wenn die Samplerate 
immer konstant ist)?

Gruß
Markus

von Thomas Z. (usbman)


Lesenswert?

Markus G. schrieb:
> Werde ich mir auch morgen anschauen, aber ansich brauche ich doch nach
> erfolgreicher Enumeration nur noch den SetInterface Request für die
> Audiofunktion oder?

Ja das ist die Theorie. Da du aber nicht sagen kannst wie usbaudio.sys 
deine Dekriptoren parsed und was für ein Feature Baum daraus für ksaudio 
gebaut wird, musst du da auch mit Fehlern rechnen. Es ist also durchaus 
möglich dass class requests auftauchen die nicht korrekt bearbeitet 
werden.
Stellt dein Code sicher dass jeder unbekannte Request auf STALL gesetzt 
wird?

Generell liegt der Fehler an deinem Device weil USB Audio devices seit 
vielen Jahren zuverlässig funktionieren.
Noch eine Frage bleibt die Ausgabe denn gestört oder gibt sich das 
wieder von alleine? Sprich braucht du ein Disconnect um ein 
funktionierendes Device zu bekommen?

Thomas

von Thomas Z. (usbman)


Lesenswert?

Markus G. schrieb:
> Das war auf jeden Fall eine sinnvolle Korrektur für die
> Langzeitstabilität.

Naja das mit der Buffer Größe ist aber nicht neu das hatte ich ja schon 
im alten Thread vorgeschlagen. Bei 44.1 k ist das genauso. Das spielt 
aber keine Rolle da du ja sowieso nur 48k machst und keine SR 
Umschaltung implementiert hast. Du streamst einfach was da so kommt!
Ich hab allerdings das Gefühl dass du dich im Kreis drehst.

Du baust ein Audiodevice machst aber Tests mit Video? Video muss zwar 
auch gehen, aber erst mal ist es ein Audio Device. Ist dir überhaupt 
klar wie viele Layer bei Video noch hinzukommen und ob die nicht 
zusätzliche Anforderungen an dein Device haben?
Seit Monaten sage ich dir schon dass du den SetSampleRate Request 
einbauen sollst den alle mir bekannten USB Audiodevice unterstützen. Du 
frikelst das ohne hin. Immerhin hast du ja inzwischen bemerkt daß es 
besser ist erst mal ohne Feedback zu arbeiten. Du suchst Fehler in 
usbadio.sys bzw ks.sys weil dein Gerät ja alles richtig macht.
Nochmal: usbaudio.sys ist mindestens seit XP stabil und weitgehend 
fehlerfrei. Das gleiche gilt für das Windows Audio Subsystem. Also schau 
dir deinen Code an.

Thomas

von Markus G. (usound)


Lesenswert?

Thomas Z. schrieb:
> Ja das ist die Theorie. Da du aber nicht sagen kannst wie usbaudio.sys
> deine Dekriptoren parsed und was für ein Feature Baum daraus für ksaudio
> gebaut wird, musst du da auch mit Fehlern rechnen. Es ist also durchaus
> möglich dass class requests auftauchen die nicht korrekt bearbeitet
> werden.
> Stellt dein Code sicher dass jeder unbekannte Request auf STALL gesetzt
> wird?
Das ist eine ziemlich gute Frage. Im Grunde habe ich einfach eine 
Standard-Struktur vom ASF-Treiber vorgegeben, der unabhängig von der 
genutzten USB-Funktion ist (Audio, HID etc.). Das Ding sieht so aus:
1
UDC_DESC_STORAGE udi_api_t udi_api_audio_out_stream = 
2
{
3
  .enable =  udi_audio_stream_out_enable,
4
  .disable =  udi_audio_stream_out_disable,
5
  .setup =  udi_audio_stream_out_setup,
6
  .getsetting =  udi_audio_stream_out_getsetting,
7
  .sof_notify =  udi_audio_stream_out_SOF_routine,
8
};
Das Ding habe ich einmal für das Control-Interface und einmal für das 
Audio-Interface.
Der enable-Callback wird immer dann aufgerufen, wenn sich an der Config 
des Interface etwas ändert (z.B. das altSetting).
Da war die Denke natürlich folgende:
Das Control-Int bekommt den Set Interface Request und macht damit 
irgendwas. Das resultiert darin, dass das alt Setting des 
Audio-Interface geändert wird.
Man denkt, super, die Callback-Funktion wird aufgerufen, dann brauche 
ich dort ja nur meinen Initialisierungscode unterbringen und die Routine 
zum Empfangen von Audiodaten aufrufen.

> Generell liegt der Fehler an deinem Device weil USB Audio devices seit
> vielen Jahren zuverlässig funktionieren.
> Noch eine Frage bleibt die Ausgabe denn gestört oder gibt sich das
> wieder von alleine? Sprich braucht du ein Disconnect um ein
> funktionierendes Device zu bekommen?
Dass der Fehler an meinem Device liegt, ist mir durchaus klar. Die 
Herangehensweise war nur die, zu versuchen zu verstehen was auf der 
Hostseite passiert, um die Auswirkungen im Device nachvollziehen zu 
können.
Disconnecten muss ich nicht zwingend, ein Stopp der Wiedergabe reicht 
(nicht Pause). Dann wird das altSetting zurückgesetzt und der Controller 
ist im Startzustand.

> Ich hab allerdings das Gefühl dass du dich im Kreis drehst.
Absolut korrekt. Im anderen Thread ging es allerdings konkret um die 
Implementierung des Feedback-Pfads.

> Du baust ein Audiodevice machst aber Tests mit Video? Video muss zwar
> auch gehen, aber erst mal ist es ein Audio Device. Ist dir überhaupt
> klar wie viele Layer bei Video noch hinzukommen und ob die nicht
> zusätzliche Anforderungen an dein Device haben?
> Seit Monaten sage ich dir schon dass du den SetSampleRate Request
> einbauen sollst den alle mir bekannten USB Audiodevice unterstützen. Du
> frikelst das ohne hin.
Ich teste mit allem möglichen: Audacity, Itunes und Youtube. Warum? Weil 
sich alle Abspielapplikationen anders zu verhalten scheinen.
Dass Videos als Test nicht ideal sind, leuchtet mir ein.

Sieht man diesen lustigen SetSampleRate Request in Wireshark? Vermutlich 
ja.
Meine 2 bisher getesteten USB-Soundkarten machen das jedenfalls nicht! 
Testdevices sind eine einfache Behringer UCA und eine ältere Roland aus 
XP-Zeiten.
Da gibt es für jede Samplerate ein eigenes Interface. Das wird beim 
Abspielen aktiviert. Das wars.
Habe das jeweils mit Wireshark geprüft, die beiden Soundkarten verhalten 
sich auf dem Log genau identisch wie meine implementierte USB-I2S-Bridge 
(sowohl beim Ein- als uach beim Ausschalten).
Deswegen wundere ich mich auch, dass da was nicht richtig funktioniert.

> Immerhin hast du ja inzwischen bemerkt daß es
> besser ist erst mal ohne Feedback zu arbeiten. Du suchst Fehler in
> usbadio.sys bzw ks.sys weil dein Gerät ja alles richtig macht.
Habe ich in keinster Weise behauptet. Wie gesagt, es ging mir nur darum, 
die Zusammenhänge zu verstehen.

Gruß
Markus

: Bearbeitet durch User
von Thomas Z. (usbman)


Lesenswert?

Zur Überprüfung ob die Requests korrekt bearbeitet werden habe ich 
früher immer den Thesycon usbio Treiber benutzt dort gibts eine App mit 
der man jeden beliebigen Request absetzen kann. Gut geeignet um das ACK 
NACK  STALL verhalten zu überprüfen. Der Nachteil ist, dass man dann 
immer den Treiber deaktivieren muss um wieder auf Audio zu kommen. Ein 
2. Rechner ist also hilfreich oder man muss deren Wizard bemühen.


hier ein Ausschnitt aus meiner USB Dogging Station
1
       ---------------- Interface Descriptor -----------------
2
bLength                  : 0x09 (9 bytes)
3
bDescriptorType          : 0x04 (Interface Descriptor)
4
bInterfaceNumber         : 0x01
5
bAlternateSetting        : 0x01
6
bNumEndpoints            : 0x01 (1 Endpoint)
7
bInterfaceClass          : 0x01 (Audio)
8
bInterfaceSubClass       : 0x02 (Audio Streaming)
9
bInterfaceProtocol       : 0x00
10
iInterface               : 0x00 (No String Descriptor)
11
12
        -------- Audio Streaming Interface Descriptor ---------
13
bLength                  : 0x07 (7 bytes)
14
bDescriptorType          : 0x24 (Audio Interface Descriptor)
15
bDescriptorSubtype       : 0x01
16
bTerminalLink            : 0x01
17
bDelay                   : 0x01
18
wFormatTag               : 0x0001 (PCM)
19
20
        ------- Audio Streaming Format Type Descriptor --------
21
bLength                  : 0x14 (20 bytes)
22
bDescriptorType          : 0x24 (Audio Interface Descriptor)
23
bDescriptorSubtype       : 0x02 (Format Type)
24
bFormatType              : 0x01 (FORMAT_TYPE_I)
25
bNrChannels              : 0x02 (2 channels)
26
bSubframeSize            : 0x02 (2 bytes per subframe)
27
bBitResolution           : 0x10 (16 bits per sample)
28
bSamFreqType             : 0x04 (supports 4 sample frequencies)
29
tSamFreq[1]              : 0x01F40 (8000 Hz)
30
tSamFreq[2]              : 0x03E80 (16000 Hz)
31
tSamFreq[3]              : 0x0AC44 (44100 Hz)
32
tSamFreq[4]              : 0x0BB80 (48000 Hz)
33
34
        ----------------- Endpoint Descriptor -----------------
35
bLength                  : 0x09 (9 bytes)
36
bDescriptorType          : 0x05 (Endpoint Descriptor)
37
bEndpointAddress         : 0x01 (Direction=OUT EndpointID=1)
38
bmAttributes             : 0x09 (TransferType=Isochronous  SyncType=Adaptive  EndpointType=Data)
39
wMaxPacketSize           : 0x00C8 (200 bytes)
40
bInterval                : 0x01 (1 ms)
41
bRefresh                 : 0x00
42
bSynchAddress            : 0x00
43
44
        ----------- Audio Data Endpoint Descriptor ------------
45
bLength                  : 0x07 (7 bytes)
46
bDescriptorType          : 0x25 (Audio Endpoint Descriptor)
47
bDescriptorSubtype       : 0x01 (General)
48
bmAttributes             : 0x01
49
bLockDelayUnits          : 0x01
50
wLockDelay               : 0x0001

Ich hab das auch noch nie anders gesehen


ich hab (bei allen Chips) sowas drin:
1
/********************************************************************
2
 *  Declaration : UINT8 DecodeRequest (void)                        *
3
 *  Description : Verteiler fuer die USB Requests                   *
4
 *  Parameter   : bmRequestType                                     *
5
 *  Return      : REQUEST_VALID or REQUEST_ERROR                    *
6
 ********************************************************************/
7
UINT8 DecodeRequest (void)
8
{
9
   switch (RequestBuf.bmRequestType & REQUESTMASK)
10
   {
11
      case _STANDART:
12
           return GetStandartRequest();
13
//#ifdef VENDOR_REQUESTS_ON
14
      case _VENDOR:
15
           return GetVendorRequest();
16
//#endif
17
      case _CLASS: 
18
           return AudioClassRequests();
19
   }
20
   return REQUEST_ERROR;
21
}     
22
23
/********************************************************************
24
 *  Declaration : UINT8 AudioClassRequests(void)                    *
25
 *  Description : Funktion zum bearbeiten der Audio Class Requests  *
26
 *  Parameter   : --                                                *
27
 *  Return      : REQUEST_VALID  oder REQUEST_ERROR                 *
28
 ********************************************************************/
29
UINT8 AudioClassRequests(void) 
30
{
31
   UINT8 result=REQUEST_ERROR;
32
   switch (RequestBuf.bmRequestType)
33
   {
34
      case _DEVICE | _CLASS | _INTERFACE:        //0x21
35
           result=AudioSetInterfaceRequest();
36
           break;
37
      case _HOST | _CLASS | _INTERFACE:          //0xA1
38
           result=AudioGetInterfaceRequest();
39
           break;
40
      case _DEVICE | _CLASS | _ENDPOINT:         //0x22
41
           result=AudioSetEndpointRequest();
42
           break;
43
      case _HOST | _CLASS | _ENDPOINT:           //0xA2
44
           result=AudioGetEndpointRequest();
45
           break;
46
   }
47
   if (result==REQUEST_VALID)
48
   {
49
      if (RequestBuf.bmRequestType & _HOST) // GetRequest ?
50
         SaveDataStagePointer(RequestBuf.wLength,&StageBuff[0]);
51
   }
52
   return result;
53
}

Sowas sollte sich ja auch irgendwo in deinem ASF code finden lassen.

Thomas

von Markus G. (usound)


Lesenswert?

Hallo Thomas,

Thomas Z. schrieb:
> hier ein Ausschnitt aus meiner USB Dogging Station
> Ich hab das auch noch nie anders gesehen

Descriptor-mäßig sieht das im Grunde identisch aus wie bei mir.


> ich hab (bei allen Chips) sowas drin:
> Sowas sollte sich ja auch irgendwo in deinem ASF code finden lassen.

Habe heute mal etwas tiefer gegraben, um zu verstehen wie der Code 
eigentlich funktioniert, den ich da benutze.
Es gestaltet sich in der Tat so, dass der Treiber aus dem ASF die 
Standard-Requests schon auf niedriger Ebene abfängt und bearbeitet. Das 
ist die Beschreibung der Routine, die als erstes seitens des USB-Moduls 
aufgerufen wird:
1
 * brief Main routine to manage the USB SETUP request.
2
 *
3
 * This function parses a USB SETUP request and submits an appropriate
4
 * response back to the host or, in the case of SETUP OUT requests
5
 * with data, sets up a buffer for receiving the data payload.
6
 *
7
 * The main standard requests defined by the USB 2.0 standard are handled
8
 * internally. The interface requests are sent to UDI, and the specific request
9
 * sent to a specific application callback.
10
 * return true if the request is supported, else the request is stalled by UDD
Das erklärt, warum der SetInterface Request überhaupt ohne mein Zutun 
bearbeitet wird (vermeintlich korrekt, jedenfalls identisch wie bei 
anderen USB-Interfaces die ich getestet habe).

Nicht Standard-Requests (z.B. SetSamplerate) landen dann in den 
Setup-Callbacks entweder des Control-Interface oder des Endpoints. Diese 
kann ich dann dort verarbeiten. Für die Sample Frequency Control habe 
ich sogar in meinem portierten Code vom AVR32 schon eine fertige 
Infrastruktur. Diese war bislang nur nicht aktiv. Ich habe es nun so 
implementiert, dass ich dies per define einschalten kann. Der 
USB-Deskriptor ändert sich dann gleich mit.
Nur ob das sinnvoll ist, finde ich eher fraglich, da ich mir dort 
zunächst eine weitere Fehlerquelle ins System hole, die es eigentlich 
zur Validierung der Grundfunktion nicht braucht.

Ich habe zum Thema SampleRateRequest nochmals in der UAC1 Spec 
recherchiert.
"5.2.3.2.3.1 Sampling Frequency Control
The Sampling Frequency Control is used to set the initial sampling 
frequency for an isochronous audio data endpoint. This allows the 
endpoints’ clock recovery system to lock onto the incoming clock much 
faster. Adaptive endpoints can benefit from this.
...
If the endpoint operates at a fixed sampling frequency, setting this 
Control has no effect."

Das heißt, dass man den SetSampleRate Request theoretisch nicht braucht, 
wenn das Device ohnehin nur eine SR unterstützt.

Durch meine LEDs im Data Received Callback (blinken 20 Hz) und im 
Interface changed Callback (wird aufgerufen wenn das alt Setting 
geändert wird) sehe ich nun woher das Problem zu kommen scheint.
Beende ich einen Stream (am einfachsten ist das Schließen eines Videos, 
auch wenn der Testcase nicht ideal ist), dann kommt auf dem 
Datenendpoint nichts mehr. Erst nach ca. 3-4 Sekunden wird das Interface 
zurückgesetzt.
Dabei werden natürlich noch Daten ausgegeben und der Buffer läuft leer. 
Wenn der Stream dann gleich wieder neustartet (springen von Video zu 
Video/Lied zu Lied), wird das altSetting nicht zurückgesetzt und der 
vorher implizierte Offset der Bufferpointer tritt zum Vorschein.

Gibt es eine Einstellung, die speziell mit dem Testcase Video 
zusammenhängt und das verzögerte Verhalten verursacht?
Ansonsten müsste ich im Code implementieren, dass immer geschaut wird, 
wenn ein paar Frames ohne Daten übermittelt wurden und dann das 
Interface und die Audioverarbeitung zu reseten.

Gruß
Markus

von Thomas Z. (usbman)


Lesenswert?

Markus G. schrieb:
> This allows the endpoints’ clock recovery system to lock onto the
> incoming clock much faster.

Das ist doch aber in meinen Augen genau der der springende Punkt. Du 
bekommst einen Request mit deiner SR und stellst dann alles was 
notwendig ist ein. Danach ist dein Stream wieder synchron. Ich finde das 
sinnvoll auch wenn nur eine SR im Deskriptor ist.

Thomas

von Thomas Z. (usbman)


Lesenswert?

Noch was zum SetInterface. Ich mach bei diesem Request intern eigentlich 
gar nichts. Ich speichere nur das Alternate in meiner Device Struktur 
damit ich das bei einem GetInterface verfügbar habe.
Bei mir ist die ganze Funktionalität in Get/SetSamplerate eingebaut.

Thomas

von Joe F. (easylife)


Lesenswert?

Markus G. schrieb:
> Dabei werden natürlich noch Daten ausgegeben und der Buffer läuft leer.
> Wenn der Stream dann gleich wieder neustartet (springen von Video zu
> Video/Lied zu Lied), wird das altSetting nicht zurückgesetzt und der
> vorher implizierte Offset der Bufferpointer tritt zum Vorschein.

Das darf aber keine Rolle spielen.
Nehmen wir mal an, dein FIFO wäre so groß, dass er 5 USB Pakete fassen 
kann.
Dann wäre der ideale Füllstand bei 3 Paketen. So groß sollte auch das 
Pre-Buffering sein.
Ab dem Moment hast du nach "oben" und nach "unten" 2 USB Pakete Platz 
zur Jitter-Kompensierung.
Wenn jetzt von deinem Player nichts mehr kommt, geht dein FIFO bereits 
nach 3 ausbleibenden Paketen in den Underrun, und du startest dein 
Pre-Buffering neu. Sobald wieder Daten kommen, werden erstmal 3 Pakete 
gebuffert, bevor du hinten was rausschickst, und alles läuft ganz normal 
weiter.

Dass das Setting mit Verzögerung gewechselt wird, hat folgenden Grund:
um Strom zu sparen möchten manche Geräte gerne den Verstärker ganz 
abschalten, wenn kein Audio mehr erwartet wird (z.B. Headsets). Da beim 
Wiedereinschalten evtl. eine kleine Verzögerung entsteht oder ein 
Knackser hörbar ist, versucht man dieses Abschalten bei kürzeren 
Audio-Pausen zu vermeiden.

: Bearbeitet durch User
von Markus G. (usound)


Lesenswert?

Joe F. schrieb:
> Das darf aber keine Rolle spielen. (...)
> Sobald wieder Daten kommen, werden erstmal 3 Pakete
> gebuffert, bevor du hinten was rausschickst, und alles läuft ganz normal
> weiter.

Hallo,

habe das nun so implementiert, dass dieser Fall abgefangen wird.
Nun läuft das Ganze einwandfrei :)
War dann wohl ein spezieller Fall, bzw. eine Besonderheit der 
Video-Klasse.

Jetzt mache ich mit dem SetSamplerate weiter, um im Betrieb die SR 
wechseln zu können. Die Request-Infrastruktur steht schon und 
funktioniert auch.
Eine grundsätzliche Frage dazu:
Kommt der Setsamplerate nur einmal am Anfang nach der Enumeration und 
wenn ich im Windows-Sound-Fenster eine andere Standard-SR auswähle oder 
kann das auch im Betrieb gewechselt werden (z.B. erst wird ein File mit 
48 kHz und dann eins mit 44,1 kHz abgespielt)?
Oder dient diese Funktion nur dazu, eine feste Standard-SR auswählen zu 
können?

Beste Grüße
Markus

von Thomas Z. (usbman)


Lesenswert?

Markus G. schrieb:
> Kommt der Setsamplerate nur einmal am Anfang nach der Enumeration und
> wenn ich im Windows-Sound-Fenster eine andere Standard-SR auswähle oder
> kann das auch im Betrieb gewechselt werden (z.B. erst wird ein File mit
> 48 kHz und dann eins mit 44,1 kHz abgespielt)?

Hallo Markus,
Set SampleRate kommt immer wenn ein Sound startet also beispielsweise 
auch wenn ein SystemSound abgespielt wird. Wenn ich mich richtig 
erinnere kannst du auch Stall zurück geben wenn du beispielsweise gerade 
einen Stream abspielst.
In diesen Fällen wird kmixer dann eine SR Konvertierung vornehmen damit 
beide Streams gemixt werden können. Du musst must SetCur und GetCur 
implementieren

Windows versucht bei ruhendem Interface immer die SR der Quelle zu 
setzen. Wenn diese nicht unterstützt wird wird auf die höchste SR 
konvertiert. Da du nur abspielst braucht das nicht viel Logik.

Thomas

von Markus G. (usound)


Lesenswert?

Thomas Z. schrieb:
> Hallo Markus,
> Set SampleRate kommt immer wenn ein Sound startet also beispielsweise
> auch wenn ein SystemSound abgespielt wird. Wenn ich mich richtig
> erinnere kannst du auch Stall zurück geben wenn du beispielsweise gerade
> einen Stream abspielst.
> In diesen Fällen wird kmixer dann eine SR Konvertierung vornehmen damit
> beide Streams gemixt werden können. Du musst must SetCur und GetCur
> implementieren

Hallo Thomas,
danke für die Infos. Die Grundfunktion habe ich soweit implementiert. 
Wie du sagtest, die Logik hält sich in Grenzen.

Werde mich nun aber zunächst um den Feedback-Endpoint kümmern. Wenn das 
läuft, kümmere ich mich nochmals intensiver um den Nebenschauplatz des 
SetSamplerate.

Gruß
Markus

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.