2016-07-13 11 views
1

Ich verwende die Callback-API von PortAudio zum Entwerfen einer Loopback-Bibliothek für die Signalverarbeitung.PortAudio-Callbacks und Ändern einer Variablen an anderer Stelle

Ich mag würde einen Zweig hinzuzufügen, die innerhalb der Callback auf eine Flagge hängt, so wie

int pa_callback(const void *inputuffer, 
       void *outputBuffer, 
       unsigned long frameCount, 
       const PaStreamCallbackTimeInfo *timeInfo, 
       PaStreamCallbackFlags statusFlags, 
       void *userData) 
{ 
    if (do_something_flag) { 
    do_something(inputBuffer, outputBuffer, frameCount); 
    } else { 
    do_something_else(inputBuffer, outputBuffer, frameCount); 
    } 

    return paContinue; 
} 

Wo do_something_flag in regelmäßigen Abständen an anderer Stelle in meinem Programm eingestellt ist.

Das Portaudio Rückruf Dokumentation heißt es:

Bevor wir beginnen, ist es wichtig zu erkennen, dass der Rückruf eine empfindliche Stelle ist. Dies liegt daran, dass einige Systeme den Rückruf in einem speziellen Thread oder Interrupt-Handler ausführen, der genauso behandelt wird wie der Rest Ihres Codes. Für die meisten modernen Systeme sind Sie nicht in der Lage, Abstürze zu verursachen, indem Sie nicht erlaubte Anrufe im Rückruf machen, aber Wenn Sie wollen, dass Ihr Code störungsfreies Audio erzeugt, müssen Sie sicherstellen, dass Sie Funktionsaufrufe vermeiden Nehmen Sie einen unbegrenzten Betrag von Zeit, um auszuführen. Genau das, was diese sind abhängig von Ihrer Plattform aber gehören fast sicher folgende: Speicher Zuweisung/Freigabe, I/O (einschließlich Datei I/O sowie Konsole I/O, wie printf()), Kontextwechsel (wie exec() oder yield()), Mutex-Operationen oder irgendetwas anderes, das sich auf das Betriebssystem verlassen könnte. Wenn Sie denken, dass kurze kritische Abschnitte sicher sind, lesen Sie bitte die Priorität Inversion.

Ich interessiere mich nicht für die Atomarität der do_something_flag. Das heißt, es ist mir egal, wie viele Zyklen es dauert, um einen korrekten Wert zu erhalten (im Rahmen des Zumutbaren). Laut der Dokumentation sieht es so aus, als ob ich keine Mutexe zum Setzen/Lesen dieser Variablen verwenden kann.

1) Was sind meine Optionen?

2) Wenn ich es global mache und es in einem anderen Teil meines Programms (ein anderer Thread) setze, was ist das absolut schlimmste, was passieren wird? Noch einmal, ich meine, in Bezug auf die Korruption von Daten bis zu dem Punkt des Programmausfalls/etc.

Gibt es einen richtigen Weg, dies zu tun?

Antwort

1

Ich bin mir nicht ganz sicher, was Sie genau machen wollen, aber ich schätze, es ist, worum es in Ihrem Titel geht - "Eine Variable anderswo ändern".

Nehmen wir dieses Beispiel: Sie haben eine Variable frequency, die sich im Laufe der Zeit ändert. Wie erreichst du das? Nun, Sie haben einen generischen Zeiger im Callback namens userData. Dies kann auf alles hinweisen - eine Datenstruktur, ein Array usw. Ich kann mich nicht wirklich daran erinnern, wie oft die Callback-Funktion aufgerufen wird (es ist ziemlich oft ... ich würde mir keine Gedanken um die Geschwindigkeit machen), aber userData erlaubt Variablen Das kann in Ihrem Haupt-Thread geändert werden, während der Zeiger im Audio-Thread es erlaubt, direkt im Speicher darauf zuzugreifen ... Mein Wissen über Thread-Sicherheit ist nicht das Beste und tut mir leid, wenn das nicht die beste Erklärung ist, aber ich kann zeige dir zumindest, wie man es durch Code macht (unten).

So mache ich es normalerweise, aber Sie müssen es nicht selbst tun; Ich habe eine Struktur an der Spitze meiner Datei wie folgt:

typedef struct { 
    float freq; 
    float vol; 
}paData; 

Offensichtlich werden Sie diese irgendwo im Code initialisiert wird (wahrscheinlich in Ihrem main Funktionsaufruf) und den Audio-Stream als solche öffnen (data ist vom Typ paData):

/* Open audio stream */ 
err = Pa_OpenStream(&(*stream), 
     &inputParameters, 
     &outputParameters, 
     SAMPLE_RATE, bufSize, paNoFlag, 
     paCallback, &data); 

Nach dem Öffnen können Sie Ihren Rückruf wie dieses:

static int pa_callback(const void *inputBffer, 
      void *outputBuffer, 
      unsigned long frameCount, 
      const PaStreamCallbackTimeInfo *timeInfo, 
      PaStreamCallbackFlags statusFlags, 
      void *userData) 
{ 
    // cast data so we can use it 
    paData *data = (paData *)userData; 

    // what's our frequency? 
    printf("%f\n", data->freq); 

    /* Do something with your code here */ 

    return paContinue; 
} 

Hoffnung, das hilft.

+0

Ja, das ist perfekt. Ich habe mich so sehr mit Thread-Sicherheit, Atomarität und globalen Variablen beschäftigt, ich habe die einfache Antwort nicht gesehen: dass PA Ihnen diese Mechanik gibt. – justynnuff

+0

Sie können sich keine Sorgen machen, dass es schwer ist, eine neue API selbst zu erlernen ... Ich hatte glücklicherweise einen großartigen Lehrer, als ich PortAudio lernte, so dass es die Dinge viel einfacher machte. Viel Glück mit dem, was du tust! –

+0

HI @ yun.cloud, ich habe vor kurzem mit der Spracherfassung und -verarbeitung mit portaudio begonnen, und ich stehe bei der Implementierung vor einigen Problemen. Ich habe die Frage hier auf stackoverflow hier gepostet (https://stackoverflow.com/questions/44645466/portaudio-real-time-audio-processing-for-continuous-input-stream). Jede Art von Hilfe wird sehr geschätzt. –