Software-Experimente mit Linux

frankl
Aktiver Hörer
Beiträge: 486
Registriert: 20.01.2013, 01:43
Wohnort: Aachen

Beitrag von frankl »

ZZTop hat geschrieben: Jetzt fährt Linux nicht mehr hoch sondern bringt Meldungen wie:
[ 95.722897 ]nouveau 0000:03........ bus MMIO write of00000002 FAULT at4188ac [ IBUS ]
Hallo Uwe,

bei solchen Problemen hilft meist die Lieblingssuchmaschine schnell weiter. In diesem Fall würde ich mal "nouveau MMIO write FAULT" oder ähnliches eingeben.

Bitte an die Moderation: Dieser Thread ist nicht für den Austausch über Konfiguratiionsprobleme von Windows 10 oder die Installation spezifischer Linux Varianten gedacht. Vielleicht kann dieser Beitrag und die vorhergehenden zu Win 10 ins Archiv verschoben werden?

Viele Grüße,
Frank
Bild
frankl
Aktiver Hörer
Beiträge: 486
Registriert: 20.01.2013, 01:43
Wohnort: Aachen

Beitrag von frankl »

Hallo Daniel,
vielen Dank für Deinen Bericht über den Einsatz von 'playhrt'. Du beschreibst ganz richtig, dass man zu Anfang ein bisschen mit den vielen Parametern herumprobieren muss. Aber es freut mich, dass Du dann eine befriedigende Einstellung finden konntest.

Deinen Vergleich verschiedener Timer finde ich auch sehr interessant. Auf den Rechnern, auf denen ich die Programme selbst probiert habe, gab es allerdings immer nur einen hochauflösenden Timer, so dass sich die Frage nach einem Vergleich nie ergeben hat.

In Deinem Skript wird zum Schluss 'playshm' aufgerufen. Ist das ein Tippfehler und es ist 'playhrt' gemeint?

Zu den 'taskset' Kommandos: Ich sorge in meinem Abspielskript auf meinem Convolver-Rechner auch dafür, dass keine ungewollten Prozesse auf dem CPU-Kern laufen, auf dem der wichtigste Prozess (in meinem Fall 'bufhrt', bei Dir 'playhrt') gestartet wird. Das mache ich so, wie von Simon vorgeschlagen, also zuerst
wird die CPU ausgeschaltet:

Code: Alles auswählen

echo 0 > /sys/devices/system/cpu/cpu1/online
und dann wieder eingeschaltet und die gewünschten Prozesse darauf mit 'taskset' gestartet.

Ich finde es bei mir übrigens am besten, das 'writeloop' (ohne realtime Priorität) und das 'bufhrt' (mit hoher realtime Priorität) auf dem gleichen CPU-Kern laufen zu lassen. Das könnte damit zu tun haben, dass unter Umständen nicht jede CPU jeden Speicherbereich gleich schnell ansprechen kann. Das muss nicht auf jeder Architektur gleich sein, aber wäre vielleicht einen Versuch wert.
Koala887 hat geschrieben: Der einzige Nachteil dabei ist, das Ganze spielt nicht gapless und bei Pause startet das Lied von vorne, was mich aber nicht besonders stört. Für den guten Klang macht man gerne ein paar Abstriche. 8)
Verstehe ich es richtig, dass Dein Skript durch 'mpd' für jedes ausgewählte Stück gestartet wird? Wenn ja, dann lässt sich in Bezug auf gapless wohl nichts verbessern.

In Deinem Skript könntest Du allerdings durchaus mehrere Stücke per 'wget' holen und dann hinterher alle diese Stücke als input-Dateien für 'sox' verwenden. Das sollte dann alle Stücke hintereinander gapless spielen. Könnte man 'mpd' dazu bringen, eine '.m3u' zu übergeben (die in jeder Zeile die URL zu einem Stück enthält)?

Viele Grüße,
Frank
Bild
Koala887
Aktiver Hörer
Beiträge: 537
Registriert: 27.12.2010, 17:23
Wohnort: Eltmann, Unterfranken

Beitrag von Koala887 »

Hallo Frank,
frankl hat geschrieben:In Deinem Skript wird zum Schluss 'playshm' aufgerufen. Ist das ein Tippfehler und es ist 'playhrt' gemeint?
über 1000 Zugriffe und du bist der Erste dem es auffällt. :wink:
Bei playhrt hatte ich die Möglichkeit vermisst, wie bei bufhrt, die shared Memory Dateien von writeloop direkt einzulesen. Also habe ich mir kurzerhand selbst ein Programm zusammen kopiert, welches die shm-Dateien per memcpy und mmap direkt in den Speicherbereich der Soundkarte kopiert. Wenn jemand Interesse hat, kann ich es gerne zur Verfügung stellen.
Davon habe ich dann auch noch eine 2. Version erstellt, bei der der komplette Fehlerauswertungs- und Statistikcode entfernt ist, was mMn noch einen Tick besser klingt :D
frankl hat geschrieben:Das mache ich so, wie von Simon vorgeschlagen, also zuerst
wird die CPU ausgeschaltet:
echo 0 > /sys/devices/system/cpu/cpu1/online
und dann wieder eingeschaltet und die gewünschten Prozesse darauf mit 'taskset' gestartet.
Hier ist es aber möglich, dass Linux neue Prozesse trotzdem auf dem Kern startet, oder laufende Prozesse dorthin verschiebt. Mit isolcpus wird das unterbunden.
frankl hat geschrieben:Könnte man 'mpd' dazu bringen, eine '.m3u' zu übergeben (die in jeder Zeile die URL zu einem Stück enthält)?
Ich bin mir jetzt nicht ganz sicher, aber ich glaube man kann auch die komplette Playlist abrufen. Da es mich bis jetzt nicht gestört hat, habe ich das aber noch nicht weiter verfolgt.

Schöne Grüße
Daniel
Bild
Bernd Peter
Aktiver Hörer
Beiträge: 3996
Registriert: 04.05.2010, 19:37

Beitrag von Bernd Peter »

Hallo Daniel,
über 1000 Zugriffe und du bist der Erste dem es auffällt.
mir ist das auch sofort aufgefallen, richtig heißt es ja playmate, oder?

Gruß

Bernd Peter
Bild
frankl
Aktiver Hörer
Beiträge: 486
Registriert: 20.01.2013, 01:43
Wohnort: Aachen

Beitrag von frankl »

Koala887 hat geschrieben:Hallo Frank,
frankl hat geschrieben:In Deinem Skript wird zum Schluss 'playshm' aufgerufen. Ist das ein Tippfehler und es ist 'playhrt' gemeint?
über 1000 Zugriffe und du bist der Erste dem es auffällt. :wink:
Bei playhrt hatte ich die Möglichkeit vermisst, wie bei bufhrt, die shared Memory Dateien von writeloop direkt einzulesen. Also habe ich mir kurzerhand selbst ein Programm zusammen kopiert, welches die shm-Dateien per memcpy und mmap direkt in den Speicherbereich der Soundkarte kopiert. Wenn jemand Interesse hat, kann ich es gerne zur Verfügung stellen.
Hallo Daniel,

danke für Deine Erklärungen. Ich gebe zu, dass mir bei meiner Frage gar nicht bewusst war, dass ich in 'playhrt' noch gar nicht die Input-Variante aus dem shared memory implementiert hatte. Ich habe das mal auf meine TODO Liste geschrieben.
Koala887 hat geschrieben: Davon habe ich dann auch noch eine 2. Version erstellt, bei der der komplette Fehlerauswertungs- und Statistikcode entfernt ist, was mMn noch einen Tick besser klingt :D
Gute Idee. Das habe ich gleich mal probiert und das macht bei mir auch den Klang einen hörbaren Tick besser. Es spielt hier vielleicht eine Rolle, dass der Code der zentralen Schleife möglichst kompakt ist, denn für die Rechenzeit sind die paar 'if'-Abfragen, durch die Code übersprungen wird, irrelevant.

Ich werde mir überlegen, ob ich so eine über einen Schalter wählbare Kompaktversion des Codes in das Programm einbaue.
Koala887 hat geschrieben:
frankl hat geschrieben:Das mache ich so, wie von Simon vorgeschlagen, also zuerst
wird die CPU ausgeschaltet:
echo 0 > /sys/devices/system/cpu/cpu1/online
und dann wieder eingeschaltet und die gewünschten Prozesse darauf mit 'taskset' gestartet.
Hier ist es aber möglich, dass Linux neue Prozesse trotzdem auf dem Kern startet, oder laufende Prozesse dorthin verschiebt. Mit isolcpus wird das unterbunden.
Das habe ich jetzt auf meinem 4-Core Odroid Convolver-Rechner auch mal probiert (dazu muss man die Kernel-Parameter-Zeile in der 'uboot.ini' suchen und editieren). Es ist sehr hübsch anzusehen, dass jetzt auf den CPUs 1 bis 3 nur noch die zugehörigen Scheduler-Kernel-Prozesse und die Programme meiner Abspiel-Pipe laufen. Die vorher da herumlungernden Prozesse (die allerdings auch nach Wochen keine CPU-Zeit verbraucht hatten) sind nun alle auf die CPU 0 verbannt. Klanglich konnte ich gegen mein vorheriges Setup aber hier keinen Unterschied ausmachen.

Viele Grüße,
Frank
Bild
Daihedz
Aktiver Hörer
Beiträge: 793
Registriert: 25.06.2010, 15:09

Beitrag von Daihedz »

Hallo in die Runde
frankl hat geschrieben: ... zum Beispiel mit 'arecord' das Eingangssignal lesen, eventuell per sox upsamplen und/oder mit brutefir falten und dann mit 'aplay' oder vielleicht besser mit meinem 'playhrt' wieder abspielen. ...

Das mache ich in meinen bisherigen Experimenten genauso, resp. mit Frank's Programmsammlung (z.B. zwischenzeitlich mit resample-soxr statt mit sox) noch etwas besser, und es funktioniert in der Regel ganz prima.

Frage: Gibt es allenfalls (noch) schlankere Alternativen zu arecord, um ein Signal, welches an der Soundkarte ansteht, in eine Pipe einzulesen? In meinem Falle würde es sich um Analog-In und/oder Spdif-In handeln.

Abspeckenwollende Grüsse
Simon
Bild
Buschel
Aktiver Hörer
Beiträge: 989
Registriert: 12.12.2013, 20:12
Wohnort: Raum Karlsruhe

Beitrag von Buschel »

Hallo zusammen,

seit ein paar Tagen beschäftige ich mit Frank´s Tools und stoße derzeit auf ein Problem, für das ich eine saubere Lösung suche. Sobald ich am Ende der pipe playhrt mit "--mmap" aufrufe bekomme ich Abbrüche. Dies geschieht nur, wenn ich brutefir ebenfalls in der pipe benutze. Als workaround hilft es, wenn ich playhrt mit "--sleep=1000000" aufrufe, was ja einer Verzögerung von 1 Sekunde entspricht. Ich vermute das liegt an noch nicht von brutefir gefüllten Puffern. Gibt es elegantere Lösungen, um diesen Fehler zu vermeiden? Ich denke da an Warteskripte, die in die pipe eingefügt werden können...

Funktioniert (mmap mit sleep notwendig):

Code: Alles auswählen

pcm.pipe_src96k_brutefir_dither24 {
	type file
	file "| sox -D -v 0.8 -r 44.1k -b 32 -c 2 -e signed -t raw - --buffer 8192 -b 64 -c 2 -e float -t raw - \
	      | resample_soxr -c 2 -B 93 -P 50 -i 44100 -o 96000 \
	      | brutefir /home/buschel/Convolver/DRC_96k_eq_stdin_stdout.conf \
	      | sox -t raw -r 96k -b 64 -c 2 -e float - --buffer 8192 -b 32 -c 2 -e signed -t raw - dither -p 24 \
	      | playhrt --verbose --verbose --stdin -k 2 -s 96000 -f S32_LE -d usbaudio --mmap --sleep=1000000"
	format "raw"
	slave.pcm null
}
Funktioniert (mmap läuft ohne sleep, wenn brutefir nicht in der pipe ist):

Code: Alles auswählen

pcm.pipe_src96k_brutefir_dither24 {
	type file
	file "| sox -D -v 0.8 -r 44.1k -b 32 -c 2 -e signed -t raw - --buffer 8192 -b 64 -c 2 -e float -t raw - \
	      | resample_soxr -c 2 -B 93 -P 50 -i 44100 -o 96000 \
	      | sox -t raw -r 96k -b 64 -c 2 -e float - --buffer 8192 -b 32 -c 2 -e signed -t raw - dither -p 24 \
	      | playhrt --verbose --verbose --stdin -k 2 -s 96000 -f S32_LE -d usbaudio --mmap"
	format "raw"
	slave.pcm null
}
Funktioniert (ohne mmap):

Code: Alles auswählen

pcm.pipe_src96k_brutefir_dither24 {
	type file
	file "| sox -D -v 0.8 -r 44.1k -b 32 -c 2 -e signed -t raw - --buffer 8192 -b 64 -c 2 -e float -t raw - \
	      | resample_soxr -c 2 -B 93 -P 50 -i 44100 -o 96000 \
	      | brutefir /home/buschel/Convolver/DRC_96k_eq_stdin_stdout.conf \
	      | sox -t raw -r 96k -b 64 -c 2 -e float - --buffer 8192 -b 32 -c 2 -e signed -t raw - dither -p 24 \
	      | playhrt --verbose --verbose --stdin -k 2 -s 96000 -f S32_LE -d usbaudio"
	format "raw"
	slave.pcm null
}
playhrt bricht ab (mmap mit brutefir):

Code: Alles auswählen

pcm.pipe_src96k_brutefir_dither24 {
	type file
	file "| sox -D -v 0.8 -r 44.1k -b 32 -c 2 -e signed -t raw - --buffer 8192 -b 64 -c 2 -e float -t raw - \
	      | resample_soxr -c 2 -B 93 -P 50 -i 44100 -o 96000 \
	      | brutefir /home/buschel/Convolver/DRC_96k_eq_stdin_stdout.conf \
	      | sox -t raw -r 96k -b 64 -c 2 -e float - --buffer 8192 -b 32 -c 2 -e signed -t raw - dither -p 24 \
	      | playhrt --verbose --verbose --stdin -k 2 -s 96000 -f S32_LE -d usbaudio --mmap"
	format "raw"
	slave.pcm null
}
Viele Grüße,
Andree
Bild
frankl
Aktiver Hörer
Beiträge: 486
Registriert: 20.01.2013, 01:43
Wohnort: Aachen

Beitrag von frankl »

Hallo Andree,

was gefällt Dir denn nicht an der --sleep Option von playhrt? Die ist genau für den Zweck, den Du hier beschreibst, eingeführt worden.

Alternativ könntest Du wohl ein ' ... | (sleep 0.2; cat) | ...' in Deine Pipe einbauen. Aber ist das besser?

In meinen Abspielskripten nutze ich auch nicht diese Option, sondern entkopple die Pipes zur Aufbereitung und zum eigentlichen Abspielen mit Hilfe von 'writeloop' und 'catloop', siehe etwa dieses Skript als Beispiel (da steht auch ein 'sleep 0.5' vor starten der Abspiel-Schleife).

Viele Grüße,
Frank
Bild
Buschel
Aktiver Hörer
Beiträge: 989
Registriert: 12.12.2013, 20:12
Wohnort: Raum Karlsruhe

Beitrag von Buschel »

Hallo Frank, hallo zusammen,

was ich mir besser vorstellen könnte, wäre evtl. über eine Abfrage des Pufferstatus loszulegen, und nicht über eine pures sleep. die von dir beschriebene sleep-Lösung innerhalb der pipe hilft mir auf jeden Fall auch, wenn ich nicht playhrt, sondern anderen Tools benutzen würde. Deswegen schon einmal vielen Dank dafür. Ich bin noch recht neu in der der Welt der pipes und deren Eigenschaften...

Bzgl. deiner Tools schaue ich mir gerade wie ich schon per PN geschrieben hatte das Verhalten von resample_soxr und playhrt genauer an. Bei resample_soxr beschäftigt mich vor allem wie sich die Parameter auf die berechneten SRC-Filter auswirken -- die Bandbreite führt bei sox und soxr zu anderen Ergebnissen. Und auch das Setzen von precision=33 führt auf den ersten Blick (ich habe nur die Impulsantwort als float64 ausgeben lassen) zu diskussionswürdigen Ergebnissen. Ich sehe z.B. nicht, dass die Sperrdämpfung höher ist als mit precision=28. Filter mit precision=33 sind aber steiler und damit länger, weil sie die höhere Dämpfung erreichen wollen. Prinzipiell sind die resaple_soxr-Filter steiler und deswegen auch länger als die über sox berechneten.

Bild
Gleiche Sperrdämpfung bei soxr prec=28 und soxr prec=33 im Vergleich zu sox -v

Bild
Ähnliches Verhalten von "resample_soxr -B 89" und "sox -rate b 93. prec=33 erzeigt steilere und damit längere Filter."

Bei playhrt suche ich nach einer anderen Implementierung der extra-bps-Nachführung, die das Sonderverhalten meines HTPC abdeckt. Problem dabei: Bei meinem HTPC läuft die interne Clock ungenau und interessanterweise als eine Art tri-state während der ersten 500-1000 Sekunden. In diesen ersten Sekunden läuft die Clock mit einer Abweichung von entweder +0.4% oder -0.4% oder +0.02%. Nach 500-1000 Sekunden fällt die Clock dann auf stabile +0.02% zurück und verbleibt dort. Die derzeitige playhrt-Implementierung macht einmalig eine Messung und Anpassung. Wenn dies in den ersten 500-100 Sekunden erfolgt, werden in meinem Fall zu hohe extra-bps angenommen, die kurz nach Einrasten der Clock auf +0.02% zu Under- oder Overflow führen.

Als generischen Lösungsansatz habe ich einen PID-Regler eingebaut. Dieser führt extra-bps immer nach und passt den Wert für extra-bps fortlaufend an die Gegebenheiten an. PID-Kern:

Code: Alles auswählen

ab_err = avgav/16 - hwbufsize/2;
ab_err_i = ab_err_i + ab_err;
ab_err_d = ab_err - ab_err_alt;
ab_err_alt = ab_err;

extrabps = (double)(ab_err*0.4 + ab_err_d*0.1 + ab_err_i*0.01);

extraerr = 1.0*bytesperframe*rate;
extraerr = extraerr/(extraerr+extrabps);
nsec = (int) (1000000000*extraerr/loopspersec);

fprintf(stderr, "playhrt: target: %ld ist: %ld e: %d ei: %d ed: %d extra: %d\n", 
  hwbufsize/2, avgav/16, ab_err, ab_err_i, ab_err_d, (int)extrabps);
Frage: Soll ich die playhrt und resample_soxr Themen hier weiter posten, oder lieber in einen eigenen Thread bringen?

Viele Grüße,
Andree
Bild
Buschel
Aktiver Hörer
Beiträge: 989
Registriert: 12.12.2013, 20:12
Wohnort: Raum Karlsruhe

Beitrag von Buschel »

Hallo nochmal,

ich konnte bei soxr das unterschiedliche Verhalten leider nicht weiter eingrenzen. Die andere Parameter sehe alle ok aus. Möglicherweise liegt das an der soxr-Version? Bei mir ist noch 0.1.1-1 installiert. Um die neueren zu installieren, müsste ich entweder eine VM mit einer neuen Linux-Version anlegen oder meinen HTPC updated. Das ist mir zu aufwändig. Ich lebe erst einmal damit, dass ich resample_soxr mit precision=28 kompiliere und "-B 89" anwende, um in etwa die gewünschten Ergebnisse zu bekommen.

Bei playhrt habe ich den Regler etwas vereinfacht und verzichte auf den I-Anteil. Damit bleibt zwar ein kleiner Fehler übrig, aber das stört nicht wirklich. Jetzt beobachte ich erst einmal wieder die Stabilität.

Viele Grüße,
Andree
Bild
Buschel
Aktiver Hörer
Beiträge: 989
Registriert: 12.12.2013, 20:12
Wohnort: Raum Karlsruhe

Beitrag von Buschel »

Hallo nochmal,

beim heutigen Updaten auf die neuere Version von resample_soxr (mit "--precision" Option) bin ich wieder über meine lokalen Änderungen an playhrt gestolpert. Das patch regelt die Variable extra_bps nach, um eine schwankende Clock auszugleichen. In meinen Setup funktioniert playhrt ansonsten nicht (siehe auch meine vorherigen Beiträge hier im Thread). Ich poste den Code hier unaufgeräumt und ohne Garantie. Vielleicht hat jemand ähnliche Probleme.

Code: Alles auswählen

diff frank_l-frankl_stereo-5321f33866ac/src/playhrt.c frankl_stereo_0.8.2/src/playhrt.c
34a35
>   fprintf(stderr, ", with PD control for clock deviation");
263c264
< "  lopps occur their number will become smaller with lower verbosity level\n"
---
> "  loops occur their number will become smaller with lower verbosity level\n"
272a274,275
> //AB    int sfd, s, moreinput, err, verbose, nrchannels, startcount, sumavg,
> //AB        stripped, innetbufsize, dobufstats, countdelay, maxbad;
274,276c277,281
<         stripped, innetbufsize, dobufstats, countdelay, maxbad;
<     long blen, hlen, ilen, olen, extra, loopspersec, nrdelays, sleep,
<          nsec, count, wnext, badloops, badreads, readmissing, avgav, checkav;
---
>         stripped, innetbufsize, dobufstats;
> //AB    long blen, hlen, ilen, olen, extra, loopspersec, nrdelays, sleep,
> //AB         nsec, count, wnext, badloops, badreads, readmissing, avgav, checkav;
> 	long blen, hlen, ilen, olen, extra, loopspersec, nrdelays, sleep,
>          nsec, count, wnext, badloops, badreads, readmissing, avgav;
281c286,287
<     double looperr, off, extraerr, extrabps, morebps;
---
> //AB    double looperr, off, extraerr, extrabps, morebps;
> 	double looperr, off, extraerr, extrabps;
292,293c298,305
<     double checktime;
<     long corr;
---
> //AB    double checktime;
> //AB    long corr;
> 
> /* AB */
> 	int ab_err = 0;
> 	int ab_err_d = 0;
> 	int ab_err_alt = 0;
> /* AB */
349c361
<     maxbad = 4;
---
> //AB    maxbad = 4;
352c364
<     corr = 0;
---
> //AB    corr = 0;
356c368
<     countdelay = 1;
---
> //AB    countdelay = 1;
421c433,434
<           maxbad = atoi(optarg);
---
> //AB          maxbad = atoi(optarg);
> 			fprintf(stderr, "playhrt: --max-bad-reads was ignored!\n");
446c459,460
<           countdelay = 0;
---
> //AB          countdelay = 0;
> 			  fprintf(stderr, "playhrt: --no-delay-stats was ignored!\n");
455c469
<           fprintf(stderr, ")\n");
---
>           fprintf(stderr, ", with PD control for clock deviation)\n");
794c808
< 	  refreshmem(iptr, s);
---
> 	  	  refreshmem(iptr, s);
829c843
< 	  refreshmem(iptr, s);
---
> 	  	  refreshmem(iptr, s);
840a855,856
> 	 /* AB: playback will start when at least 10 ms are buffered */
> 	 /* AB: startcount = (int)((1.0*10000000)/nsec+1.0); */
850d865
<       checktime = 0;
853a869,874
> 		  if (verbose)
> 			if (count == startcount) {
> 				clock_gettime(CLOCK_MONOTONIC, &mtimecheck);
> 				fprintf(stderr, "playhrt: Start playback time (%ld sec %ld nsec).\n",
>                          mtime.tv_sec, mtime.tv_nsec);
> 			}
876,902c897,910
<                   if (verbose > 1)
<                       fprintf(stderr, "playhrt: Average available buffer: %ld (%ld sec %ld nsec).\n", avgav/16, mtime.tv_sec, mtime.tv_nsec);
<                   if (checktime == 0.0 && count > startcount+30000) {
<                        checktime = 1.0*mtime.tv_sec + mtime.tv_nsec/1000000000.0;
<                        checkav = avgav/16;
<                        corr = 1;
<                   }
<                   if (corr && avgav/16 > checkav + hwbufsize*3/10) {
<                        extrabps += (double)((avgav/16-checkav)*bytesperframe)/(mtime.tv_sec*1.0+mtime.tv_nsec/1000000000.0-checktime);
<                        extraerr = 1.0*bytesperframe*rate;
<                        extraerr = extraerr/(extraerr+extrabps);
<                        nsec = (int) (1000000000*extraerr/loopspersec);
<                        corr = 0;
<                        fprintf(stderr, "playhrt: Avoiding buffer underrun! Please use option \n"
<                                "      --extra-bytes-per-second=%d\n"
<                                "on next call.\n", (int)extrabps);
<                   }
<                   if (corr && avgav/16 < checkav - hwbufsize*3/10) {
<                        extrabps += (double)((avgav/16-checkav)*bytesperframe)/(mtime.tv_sec*1.0+mtime.tv_nsec/1000000000.0-checktime);
<                        extraerr = 1.0*bytesperframe*rate;
<                        extraerr = extraerr/(extraerr+extrabps);
<                        nsec = (int) (1000000000*extraerr/loopspersec);
<                        corr = 0;
<                        fprintf(stderr, "playhrt: Avoiding buffer overrun! Please use option \n"
<                                "      --extra-bytes-per-second=%d\n"
<                                "on next call.\n", (int)extrabps);
<                   }
---
> 				  /* implement PD-controller, target = hwbufsize/2 */
> 				  ab_err = avgav/16 - hwbufsize/2;
> 				  ab_err_d = ab_err - ab_err_alt;
> 				  ab_err_alt = ab_err;
> 				  extrabps = (double)(ab_err*0.4 + ab_err_d*0.1);
> 
> 				  /* calculated required sleep time for adapted fill-rate */
> 				  extraerr = 1.0*bytesperframe*rate;
>                   extraerr = extraerr/(extraerr+extrabps);
>                   nsec = (int) (1000000000*extraerr/loopspersec);
> 
> 				  if (verbose > 1)
> 				  	fprintf(stderr, "playhrt: At %ld sec. avail: %5ld e: %4d ed: %4d extrabps: %4d\n", 
> 						mtime.tv_sec, avgav/16, ab_err, ab_err_d, (int)extrabps);
919,921d926
< 
< 
<           /* we refresh the new data before and directly after the  sleep before commiting */
923,933d927
< 
<           /* debug:  check that we really sleep to some time in the future */
<           if (countdelay) {
<             clock_gettime(CLOCK_MONOTONIC, &mtimecheck);
<             if (mtimecheck.tv_sec > mtime.tv_sec || (mtimecheck.tv_sec == mtime.tv_sec && mtimecheck.tv_nsec > mtime.tv_nsec))
<                 nrdelays += 1;
<           }
<           if (verbose > 1 && nrdelays > 0 && count % 4096 == 0) {
<               fprintf(stderr, "playhrt: Number of delayed loops: %ld (%ld sec %ld nsec).\n", nrdelays, mtime.tv_sec, mtime.tv_nsec);
<           }
< 
935c929
< 	  refreshmem(iptr, s);
---
> 	      refreshmem(iptr, s);
937,949d930
<           if (s < 0) {
<               fprintf(stderr, "playhrt: Read error.\n");
<               exit(22);
<           } else if (s < ilen) {
<               badreads++;
<               readmissing += (ilen-s);
<               if (verbose)
<                   fprintf(stderr, "playhrt: Bad read, %ld bytes missing at %ld.%ld.\n", (ilen-s), mtime.tv_sec, mtime.tv_nsec);
<               if (badreads >= maxbad) {
<                   fprintf(stderr, "playhrt: Had %d bad reads . . . exiting.\n", maxbad);
<                   break;
<               }
<           }
961,967d941
<         if (corr) {
<             morebps = (double)((avgav/16-checkav)*bytesperframe)/(mtime.tv_sec*1.0+mtime.tv_nsec/1000000000.0-checktime);
<             if (morebps >= 1.0 || morebps <= -1.0)
<                 fprintf(stderr, "playhrt: Suggesting option \n"
<                              "      --extra-bytes-per-second=%d\n"
<                              "on future calls.\n", (int)(extrabps+morebps));
<         }
Nur in frankl_stereo_0.8.2/src: version.h.
Grüße,
Andree

PS: Ein anderes patch, das ich seit Jahren benutze, ist ein Fix für brutefir, um bei ALSA under-/overflow auch das richtige ALSA device anzuzeigen. Der Fix stammt ursprünglich hier aus dem Forum von Tobias (Pittiplatsch).

Code: Alles auswählen

diff brutefir-1.0o-original/bfio_alsa.c brutefir-1.0o/bfio_alsa.c
437c437
<     fd2as[pollfd.fd].device = settings->device;
---
>     fd2as[pollfd.fd].device = estrdup(settings->device);

diff brutefir-1.0o-original/brutefir.c brutefir-1.0o/brutefir.c
2c2
<  * (c) Copyright 2001 - 2006, 2009, 2013, 2016 -- Anders Torger
---
>  * (c) Copyright 2001 - 2006, 2009, 2013, 2016, 2017 -- Anders Torger
22c22
< BruteFIR v1.0o (November 2016)                                \
---
> BruteFIR v1.0o+ (May 2017)    
Bild
Daihedz
Aktiver Hörer
Beiträge: 793
Registriert: 25.06.2010, 15:09

Playhrt Manieren im Umgang mit kleinen Puffern beibringen ...

Beitrag von Daihedz »

Ausgangslage:

Mit der eigentlich genialen Funktionsweise von playhrt, den Speicher der Soundkarte in kurzen und genauen Zeitintervallen sequenziell und häppchenweise mit den gerade benötigten Audiodaten zu befüllen, wird nebst der Clock der Soundkarte eine zweite Clock, nämlich dieser Gebertakt von playhrt, in die Übertragungskette eingefügt. Und damit wird gleich die Problematik zweier asynchroner Clocks mit installiert: Da beide Clocks nicht perfekt synchronisiert sein können, kommt es früher oder später zu over- oder underruns.

Damit die asynchronen Clocks nicht gleich zu xrun’s führen, muss mittels des Parameters –extra-bytes nachgebessert werden: Mit --extra-bytes-per-second=+/-nnn wird playhrt angewiesen, statisch und steuernd die Befüllung der Speicher pro Zeiteinheit anzupassen. Näheres dazu gibt es in den Hilfetexten von playhrt.

Die Anpassung mit --extra-bytes-per-second jedoch funktioniert nie ganz exakt. Denn mit --extra-bytes-per-second kann bloss eine Annäherung an die präzise erforderliche Pufferbefüllung erreicht werden. Deshalb kommt es trotz einer noch so sorgfältigen Bemessung von --extra-bytes-per-second unweigerlich zu xruns. Lediglich die Zeitspanne bis zum Auftretens kann damit bis zu einer gegebenen Limite verlängert werden.

Bei gleicher Befüllungs- und Entleerungsynamik laufen kleine Puffer in der Natur der Sache schneller voll, resp. leer als grosse Puffer. Deshalb ist die Zeitspanne bis zum Auftreten von xruns auch von der Puffergrösse abhängig. Und deshalb wird in der Praxis pragmatisch einfach mal die Puffergrösse erhöht, wenn xruns zu häufig auftreten.

Eleganter wäre eine dynamische Nachführungsmöglichkeit der Pufferdynamik während des Betriebs. Wird der Puffer zu voll, müsste pro Zeiteinheit kompensierend weniger befüllt werden, oder aber es müssten mehr Daten verbraucht werden. Und umgekehrt. Playhrt kann aber die Befüllung mittels --extra-bytes-per-second in den bisherigen Version nicht während des laufenden Betriebs dynamisch anpassen.

Die Problematik verschärft sich weiter, wenn mittels --mmap memory mapping erfolgt. In diesem, eigentlich zu bevorzugenden Betriebszustand bricht playhrt die Übertragung von Audiodaten gänzlich ab, wenn die Bedingung für einen xrun erfüllt sind.

Messwerte:

Als Beispiel sei ein konkretes Setup gewählt, in welchem als Ausgangs-Soundkarte eine RME HDSP 9632 verbaut ist. Beispielhaft soll nun Playhrt mit folgender Befehlszeile gestartet werden:

$ playhrt …. -b0 -c256 -e0 -k8 -M -s96000 …

Mit -b0 errechnet playhrt autonom den möglichst kleinsten Eingangspuffer, -c256 setzt den HW-Puffer der Soundkarte auf 256Byte, -e0 ist gleichbedeutend mit --extra-bytes-per-second=0, -k8 definiert die Anzahl Audiokanäle und -s96000 definiert die Rate. Diese Befehlszeile mit b0, d.h. ohne extra-bytes, führt zum sofortigen Abbruch.

Das weitere Experimentieren mit den extra-bytes legt offen, dass auf diesem System zwischen -e-135 und -e136 der kritische Umschlagspunkt liegt:

$ playhrt …. -b-135 -c256 -e-135 -k8 -M -s96000 …
befüllt die Puffer wesentlich schneller, als sie verbraucht werden, und erwirkt aufrund der Überfüllung einen Abbruch der Wiedergabe schon nach 17 Sekunden.

$ playhrt …. -b-136 -c256 -e-136 -k8 -M -s96000 …
befüllt die Puffer bloss ein klein wenig zu langsam, als sie verbraucht werden, und erwirkt aufgrund der Entleerung einen Abbruch der Wiedergabe nach 758 Sekunden.

Diese Werte sind nicht genau reproduzierbar. Denn der playhrt taktende Quarz auf dem Motherboard und der Quarz auf der Soundkarte driften nach jeweils eigener Dynamik erwartungsgemäss hin- und her. Unter der Annahme, dass das System dennoch einigermassen stabil bleibt, wäre somit der Sweet-Spot für die extra-bytes mit -136 gefunden.

Die einstellbare HW-Puffergrösse dieser spezifischen Soundkarte liegt nun zwischen 256Bytes und 16384Bytes. Unter der Annahme einer linearen Beziehung zwischen der Funktionsdauer und der HW-Puffergrösse lässt sich nun die stabile Funktionsdauer entsprechend und approximativ wie folgt erhöhen:

256Bytes - 12 Minuten
1024Bytes - 48 Minuten
4096Bytes - 3 Stunden
16384Bytes - 12 Stunden

Pragmatisch wird nun in den meisten Fällen wohl eine Einstellung des HW-Puffers zwischen 2048Bytes und 8192 gewählt werden. Passt schon ... Aber ganz befriedigend ist diese Schicksalsergebenheit dennoch nicht, und insbesondere dann nicht, wenn, aus welchem Grund auch immer, kleine Puffer eingestellt werden sollten.

Workaround - Die RME, ihr Treiber, die /proc/asound/... pseudofiles und ein kleines skript :

Zu Hilfe kommt nun eine Einstellmöglichkeit des Linux ALSA-Treibers der RME HDSP 9632: Der Treiber lässt eine dynamische Variation der ClockRate, als DDS bezeichnet, um theoretische +-5000Hz zu (so wie der Windows-Treiber auch). Aber mit ALSA bloss theoretisch. Denn der Treiber ist offenbar fehlerhaft implementiert, weswegen leider ausschliesslich positive geradzahlige Werte umgesetzt werden. Die Eingabe negativer Werte verursacht stattdessen ohne weitere Konsequenzen eine Fehlermeldung.

Im Testsystem erfolgt die Einstellung der DDS mittels amixer unter numid=30. Somit kann mittels
$ amixer -c0 cset numid=30 0
und
$ amixer -c0 cset numid=30 2
nach Bedarf dynamisch die Clock der Soundkarte um je 2Hz hinauf- und zurückgeschaltet werden.

Eine leicht höhere Clockrate bewirkt logischerweise einen leicht höheren Datenverbrauch, und somit eine etwas intensivere Entleerung des HW-Speichers.

Für den Aufbau einer Regelung mit Hysterese muss der dynamisch aktuelle Speicherinhalt bekannt sein. Die Stell- und Regelgrössen für diese Regelung finden sich in den Pseudodateien unter

/proc/asound/card0/pcm0p/sub0/hw_params
buffer_size: 256
und
/proc/asound/card0/pcm0p/sub0/status
avail: nnn

Unmittelbar zu Beginn der Aktivität von Playhrt ist ${avail} leicht grösser als ${buffer_size}/2. Im laufenden Betrieb dann vergrössert oder verkleinert sich ${avail} in Abhängigkeit von den eingestellten extra-bytes.

Playhrt bricht ab, wenn
${avail} = ${buffer_size}
oder
${avail} <= ${buffer_size}/2

Anders herum: Damit playhrt nicht abbricht, muss
${buffer_size}/2 < ${avail} < ${buffer_size}
betragen.

In Kenntnis dieser Werte kann nun der Füllzustand des HW-Puffers dynamisch über den Datenverbrauch (mittels Umschaltung der DDS ) geregelt und in einem funktionalen Bereich behalten werden.
Im obigen Setup wurden die Grenzwerte für die Hysterese auf
0.6*${buffer_size} < ${avail} < 0.85*${buffer_size}
eingestellt.

Ein bash-script fragt in einer Schleife alle 10 Sekunden den Wert von ${avail} ab und stellt gemäss den Grenzwerten der Hysterese bei Bedarf die DDS nach:

Bei
${avail} > 0.85*${buffer_size} wird die DDS auf 2 geschaltet
-->> Der Pufferstand sinkt in der Folge ganz langsam und stetig

Bei
${avail} < 0.6*${buffer_size} wird die DDS auf 0 geschaltet
-->> Der Pufferstand steigt in der Folge angsam und stetig an

Somit wird ${avail} im funktionalen Bereich gehalten.

--extra-bytes-per-second wird sinnvollerweise dergestalt eingestellt, dass die Puffer der Soundkarte ohne die Regelung laufend überfüllt würden. Im Testsystem wurde mit einer kleinen Sicherheitsmarge gegenüber dem experimentell erhobenen Grenzwert bei -135 eine etwas intensivere Befüllung mit einem Wert von -130 eingestellt.

Resultat / Ausblick:

Der Regelkreis funktioniert bestens. Das System läuft dank dieses kleinen Skripts selbst mit dem kleinsten, einstellbaren HW-Puffer von 256Byte beliebig lang stabil.

Ein Leider noch, zuletzt: Der beschriebene Lösungsansatz mittels DDS ist ausschliesslich Systemen vorbehalten, in welchen RME-Soundkarten verbaut sind. Eine universelle Anwendbarkeit, d.h. ohne DDS, würde dadurch erschlossen, wenn playhrt die (externe) dynamische Nachführung der extra-bytes zulassen würde. Besser noch - möglicherweise wäre in einer künftigen Version von playhrt gleich die Implementation einer internen Nachführung denkbar, analog zur beschriebenen externen Lösung.
Bild
Buschel
Aktiver Hörer
Beiträge: 989
Registriert: 12.12.2013, 20:12
Wohnort: Raum Karlsruhe

Beitrag von Buschel »

Hallo,

das Problem von asynchronen Clocks verfolgt mich auch schon eine Weile. Der playhrt-Patch aus meinem vorherigen Beitrag in diesem Thread regelt extra-bytes laufend nach und folgt (bei meinem PC auftretenden) Schwankungen der Clock. Geregelt wird auch auf einen gewünschten Pufferfüllgrad hin. Das funktioniert auch ohne RME oder zusätzliches Skript, und unabhängig davon, ob die Clock zu schnell oder zu langsam läuft. Erst mit diesem Patch läuft playhrt bei mir robust.

Grüße,
Andree
Bild
Daihedz
Aktiver Hörer
Beiträge: 793
Registriert: 25.06.2010, 15:09

Beitrag von Daihedz »

Hallo Andree

Du präsentierst genau sowas, wie ich es mir im regulären Source-Code von playhrt 0.9 wünschen würde. Erst damit würde playhrt eigentlich robust funktional werden. Solange das nicht der Fall ist, wird playhrt eher eine Nischenlösung bleiben, für unabschreckbare, bastelfreudige und stoische Selbsthelfer ...

Ich verstehe meinen Workaround in diesem Sinne als doppelt hölzerner Umweg. Doppelt, da ich C nicht beherrsche. Deine Lösung ist natürlich wesentlich eleganter und direkter, und eigentlich machen beide Ansätze in etwa dasselbe, ausgehend vom Monitoring des HW-Speichers:

...
> /* implement PD-controller, target = hwbufsize/2 */
> ab_err = avgav/16 - hwbufsize/2;
> ab_err_d = ab_err - ab_err_alt;
> ab_err_alt = ab_err;
> extrabps = (double)(ab_err*0.4 + ab_err_d*0.1);
...

Superschön!

Aber da ist noch ein kleines Problem, welches Du mit Deinem Garantie-Dysclaimer vorwegnimmst: Nachteil Deiner Lösung (und wohl jeder Patch-Lösung) ist, dass sie an eine bestimmte Version (0.8.2) von playhrt gebunden ist? Oder habe ich etwas falsch verstanden? Ich schaffe es jedenfalls nicht, an eine 0.8.2 heranzukommen. Und wenn ich Deinen Patch über die 0.8. laufen lassen möchte, dann antwortet mir

$ cat /home/privat/playhrt_buschelpatch.txt | patch -p0 --dry-run
schönde mit
patch: **** Only garbage was found in the patch input.

Das war's dann schon.

Fazit: Ich würde nur allzu gerne Deine Lösung patchen, schaffe es aber nicht. Oder noch lieber hätte ich in näherer Zukunft von Frank von playhrt eine 0.9 angeboten bekommen.

Ungepätschte Grüsse
Simon
Bild
Buschel
Aktiver Hörer
Beiträge: 989
Registriert: 12.12.2013, 20:12
Wohnort: Raum Karlsruhe

Beitrag von Buschel »

Gute Morgen Simon,

die Version 0.8.2 ist die von mir so benannte lokale Version (0.8.1 war ein anderer lokaler Hack in resample_soxr, den ich seit Frank´s Änderung vom 25.01.2020 nicht mehr brauche). Der Patch basiert auf Frank´s Version 0.8, die ich hier heruntergeladen habe: https://bitbucket.org/frank_l/frankl_stereo/src/master/ . Nach Entpacken landet der aktuelle Code (heute gezogen) unter dem Pfad frank_l-frankl_stereo-7f12b1796e76.

Damit jetzt alles so funktioniert wie es soll, habe ich den Patch nochmal frisch erzeugt und dann kurz getestet, ob er auch ohne Fehler appliziert werden kann.

Patch erzeugt über:

Code: Alles auswählen

diff frank_l-frankl_stereo-5321f33866ac/src/playhrt.c frankl_stereo_0.8.2/src/playhrt.c > playhrt_pd_control.patch
Patch angewendet mit:

Code: Alles auswählen

patch frank_l-frankl_stereo-7f12b1796e76/src/playhrt.c < playhrt_pd_control.patch
Der Patch selbst:

Code: Alles auswählen

34a35
>   fprintf(stderr, ", with PD control for clock deviation by Andree Buschmann");
263c264
< "  lopps occur their number will become smaller with lower verbosity level\n"
---
> "  loops occur their number will become smaller with lower verbosity level\n"
272a274,275
> //AB    int sfd, s, moreinput, err, verbose, nrchannels, startcount, sumavg,
> //AB        stripped, innetbufsize, dobufstats, countdelay, maxbad;
274,276c277,281
<         stripped, innetbufsize, dobufstats, countdelay, maxbad;
<     long blen, hlen, ilen, olen, extra, loopspersec, nrdelays, sleep,
<          nsec, count, wnext, badloops, badreads, readmissing, avgav, checkav;
---
>         stripped, innetbufsize, dobufstats;
> //AB    long blen, hlen, ilen, olen, extra, loopspersec, nrdelays, sleep,
> //AB         nsec, count, wnext, badloops, badreads, readmissing, avgav, checkav;
> 	long blen, hlen, ilen, olen, extra, loopspersec, nrdelays, sleep,
>          nsec, count, wnext, badloops, badreads, readmissing, avgav;
281c286,287
<     double looperr, off, extraerr, extrabps, morebps;
---
> //AB    double looperr, off, extraerr, extrabps, morebps;
> 	double looperr, off, extraerr, extrabps;
292,293c298,305
<     double checktime;
<     long corr;
---
> //AB    double checktime;
> //AB    long corr;
> 
> /* AB */
> 	int ab_err = 0;
> 	int ab_err_d = 0;
> 	int ab_err_alt = 0;
> /* AB */
349c361
<     maxbad = 4;
---
> //AB    maxbad = 4;
352c364
<     corr = 0;
---
> //AB    corr = 0;
356c368
<     countdelay = 1;
---
> //AB    countdelay = 1;
421c433,434
<           maxbad = atoi(optarg);
---
> //AB          maxbad = atoi(optarg);
> 			fprintf(stderr, "playhrt: --max-bad-reads was ignored!\n");
446c459,460
<           countdelay = 0;
---
> //AB          countdelay = 0;
> 			  fprintf(stderr, "playhrt: --no-delay-stats was ignored!\n");
455c469
<           fprintf(stderr, ")\n");
---
>           fprintf(stderr, ", with PD control for clock deviation)\n");
794c808
< 	  refreshmem(iptr, s);
---
> 	  	  refreshmem(iptr, s);
829c843
< 	  refreshmem(iptr, s);
---
> 	  	  refreshmem(iptr, s);
840a855,856
> 	 /* AB: playback will start when at least 10 ms are buffered */
> 	 /* AB: startcount = (int)((1.0*10000000)/nsec+1.0); */
850d865
<       checktime = 0;
853a869,874
> 		  if (verbose)
> 			if (count == startcount) {
> 				clock_gettime(CLOCK_MONOTONIC, &mtimecheck);
> 				fprintf(stderr, "playhrt: Start playback time (%ld sec %ld nsec).\n",
>                          mtime.tv_sec, mtime.tv_nsec);
> 			}
876,902c897,910
<                   if (verbose > 1)
<                       fprintf(stderr, "playhrt: Average available buffer: %ld (%ld sec %ld nsec).\n", avgav/16, mtime.tv_sec, mtime.tv_nsec);
<                   if (checktime == 0.0 && count > startcount+30000) {
<                        checktime = 1.0*mtime.tv_sec + mtime.tv_nsec/1000000000.0;
<                        checkav = avgav/16;
<                        corr = 1;
<                   }
<                   if (corr && avgav/16 > checkav + hwbufsize*3/10) {
<                        extrabps += (double)((avgav/16-checkav)*bytesperframe)/(mtime.tv_sec*1.0+mtime.tv_nsec/1000000000.0-checktime);
<                        extraerr = 1.0*bytesperframe*rate;
<                        extraerr = extraerr/(extraerr+extrabps);
<                        nsec = (int) (1000000000*extraerr/loopspersec);
<                        corr = 0;
<                        fprintf(stderr, "playhrt: Avoiding buffer underrun! Please use option \n"
<                                "      --extra-bytes-per-second=%d\n"
<                                "on next call.\n", (int)extrabps);
<                   }
<                   if (corr && avgav/16 < checkav - hwbufsize*3/10) {
<                        extrabps += (double)((avgav/16-checkav)*bytesperframe)/(mtime.tv_sec*1.0+mtime.tv_nsec/1000000000.0-checktime);
<                        extraerr = 1.0*bytesperframe*rate;
<                        extraerr = extraerr/(extraerr+extrabps);
<                        nsec = (int) (1000000000*extraerr/loopspersec);
<                        corr = 0;
<                        fprintf(stderr, "playhrt: Avoiding buffer overrun! Please use option \n"
<                                "      --extra-bytes-per-second=%d\n"
<                                "on next call.\n", (int)extrabps);
<                   }
---
> 				  /* implement PD-controller, target = hwbufsize/2 */
> 				  ab_err = avgav/16 - hwbufsize/2;
> 				  ab_err_d = ab_err - ab_err_alt;
> 				  ab_err_alt = ab_err;
> 				  extrabps = (double)(ab_err*0.4 + ab_err_d*0.1);
> 
> 				  /* calculated required sleep time for adapted fill-rate */
> 				  extraerr = 1.0*bytesperframe*rate;
>                   extraerr = extraerr/(extraerr+extrabps);
>                   nsec = (int) (1000000000*extraerr/loopspersec);
> 
> 				  if (verbose > 1)
> 				  	fprintf(stderr, "playhrt: At %ld sec. avail: %5ld e: %4d ed: %4d extrabps: %4d\n", 
> 						mtime.tv_sec, avgav/16, ab_err, ab_err_d, (int)extrabps);
919,921d926
< 
< 
<           /* we refresh the new data before and directly after the  sleep before commiting */
923,933d927
< 
<           /* debug:  check that we really sleep to some time in the future */
<           if (countdelay) {
<             clock_gettime(CLOCK_MONOTONIC, &mtimecheck);
<             if (mtimecheck.tv_sec > mtime.tv_sec || (mtimecheck.tv_sec == mtime.tv_sec && mtimecheck.tv_nsec > mtime.tv_nsec))
<                 nrdelays += 1;
<           }
<           if (verbose > 1 && nrdelays > 0 && count % 4096 == 0) {
<               fprintf(stderr, "playhrt: Number of delayed loops: %ld (%ld sec %ld nsec).\n", nrdelays, mtime.tv_sec, mtime.tv_nsec);
<           }
< 
935c929
< 	  refreshmem(iptr, s);
---
> 	      refreshmem(iptr, s);
937,949d930
<           if (s < 0) {
<               fprintf(stderr, "playhrt: Read error.\n");
<               exit(22);
<           } else if (s < ilen) {
<               badreads++;
<               readmissing += (ilen-s);
<               if (verbose)
<                   fprintf(stderr, "playhrt: Bad read, %ld bytes missing at %ld.%ld.\n", (ilen-s), mtime.tv_sec, mtime.tv_nsec);
<               if (badreads >= maxbad) {
<                   fprintf(stderr, "playhrt: Had %d bad reads . . . exiting.\n", maxbad);
<                   break;
<               }
<           }
961,967d941
<         if (corr) {
<             morebps = (double)((avgav/16-checkav)*bytesperframe)/(mtime.tv_sec*1.0+mtime.tv_nsec/1000000000.0-checktime);
<             if (morebps >= 1.0 || morebps <= -1.0)
<                 fprintf(stderr, "playhrt: Suggesting option \n"
<                              "      --extra-bytes-per-second=%d\n"
<                              "on future calls.\n", (int)(extrabps+morebps));
<         }
ich hoffe jetzt funktioniert das patchen bei dir und du kannst ausprobieren.

Viele Grüße,
Andree
Bild
Antworten