mozilla / cubeb

Cross platform audio library
ISC License
439 stars 124 forks source link

modify example code to be self-sufficient, and compile without changes #709

Open ad8e opened 2 years ago

ad8e commented 2 years ago

This modifies the starting example so that it will compile and run as-is. (The new user experience is discouraging when the starting example requires multiple changes and digging through documentation, and this addresses that.)

The git diff is messed up because it is embedded inside a comment. Here is a more readable diff, with explanations.

@@ -1,15 +1,26 @@
+    #include "stdio.h"
+    #include "cubeb/cubeb.h"
+    #ifdef _WIN32
+    #define WIN32_LEAN_AND_MEAN
+    #include <Windows.h>
+    #include <Objbase.h>
+    #else
+    #include <unistd.h>
+    #endif

This adds the necessary headers.

+    #define PIPE_INPUT_TO_OUTPUT true

When the user doesn't have a microphone, the starting example fails to run, with little indication of what the problem is. I added a flag which switches the behavior to output-only. Above the code, I also added a comment to explain the failure: "If you receive "Could not open the stream", you likely do not have a microphone. In that case, change PIPE_INPUT_TO_OUTPUT from true to false."

I left the input-to-output behavior as the default out of conservativeness for this patch. You can switch #define PIPE_INPUT_TO_OUTPUT true to false, to choose an output-only default. This would be more likely to run on the first try.

     long data_cb(cubeb_stream * stm, void * user,
                  const void * input_buffer, void * output_buffer, long nframes)
     {
-      const float * in  = input_buffer;
-      float * out = output_buffer;
+      const float * in = (float *)input_buffer;
+      float * out = (float *)output_buffer;

C++ doesn't allow this implicit conversion, whereas C does. This helps it compile in C++ without affecting C.

       for (int i = 0; i < nframes; ++i) {
         for (int c = 0; c < 2; ++c) {
+    #if PIPE_INPUT_TO_OUTPUT
           out[2 * i + c] = in[i];
+    #else
+          out[2 * i + c] = (float)((i * 123) % 200) / 10000.f;
+    #endif

This is the fallback I chose when the input-to-output behavior is disabled. It is a buzzy tone that doesn't sound great. I chose this one because it is simple and doesn't add state; more conventional tones like sines or sawtooth would run up against the buffer size boundary, creating a sharp jump. With this modulo tone, the sharp jumps are part of the tone, so the buffer boundaries are not noticeable.

         }
       }
       return nframes;
@@ -22,6 +33,9 @@

 int main() {
+    #if _WIN32
+      CoInitializeEx(NULL, COINIT_MULTITHREADED);
+    #endif

COM issues were hard to diagnose and fix when I first tried cubeb a while back; this removes that problem for the new user example. The existing documentation was not in a place that is easy for new users to find quickly. I don't know about the experience now.

    cubeb * app_ctx;
     cubeb_init(&app_ctx, "Example Application", NULL);
     int rv;
@@ -52,7 +66,11 @@
     input_params.prefs = CUBEB_STREAM_PREF_NONE;
     cubeb_stream * stm;
     rv = cubeb_stream_init(app_ctx, &stm, "Example Stream 1",
+    #if PIPE_INPUT_TO_OUTPUT
                            NULL, &input_params,
+    #else
+                             NULL, NULL,
+    #endif
                            NULL, &output_params,
                            latency_frames,
                            data_cb, state_cb,
@@ -69,7 +87,11 @@
     for (;;) {
       cubeb_stream_get_position(stm, &ts);
       printf("time=%llu\n", ts);
+    #if _WIN32
+        Sleep(1);
+    #else
       sleep(1);
+    #endif

My Windows did not have sleep(), so I used Sleep() instead.

     }
     rv = cubeb_stream_stop(stm);
     if (rv != CUBEB_OK) {
@@ -79,4 +101,3 @@
     cubeb_stream_destroy(stm);
     cubeb_destroy(app_ctx);
 }

Also, the callbacks have been shuffled to above main(), to form a single file that can be used as-is. I wrote the compilation command for g++ (msys2), and left the user to figure out Visual Studio.