Stereo audio device playing mono

After losing my mind, I was able to isolate the problem. It’s just a limitation of AirPods (and perhaps other bluetooth devices). The problem occurs when the AirPods are opened as both a playback device and a record device. Opening them as a record device forces the playback to mono.

The behavior is identical any time the AirPods are opened for recording by any other application. I tested this in quicktime and audacity.

I was hung up on the fact that SDL treats the playback instance of the AirPods as a distinct device (with a distinct id) from the record instance, and the specs don’t share any memory – but of course, SDL and the sound card don’t have authority over what the AirPods want to do.

I don’t have a device to test with, but I realize this might also be true for audio jack plug-in headsets, since a conventional 1/8" TRS connectors can only carry two analog signals at a time.

The solution for me is probably to open the default recording device only when I need it, and then close it when I’m done. There’d be an associated performance tradeoff, but probably worth it.

Hope this comes in handy to anyone else who runs into the same problem. Here’s the code I used to confirm the hypothesis:

    char *default_record_device_name;
    char *default_playback_device_name;

    SDL_AudioSpec r_spec;
    SDL_AudioSpec p_spec;

    SDL_GetDefaultAudioInfo(&default_record_device_name, &r_spec, 1);
    SDL_GetDefaultAudioInfo(&default_playback_device_name, &p_spec, 0);

    fprintf(stderr, "Default record device name: %s, spec channels: %d\n", default_record_device_name, r_spec.channels);
    fprintf(stderr, "Default playback device name: %s, spec channels: %d\n", default_playback_device_name, p_spec.channels);

    // p_spec.freq = 44100;
    // p_spec.format = AUDIO_S16LSB;
    // p_spec.channels = CHANNELS;
    // p_spec.samples = CHUNK_SIZE;
    // p_spec.callback = audio_callback;
    // ^ These lines have no effect on the problem

    SDL_AudioSpec r_obtained;
    SDL_AudioSpec p_obtained;

    fprintf(stderr, "Opening playback device in ");
    for (uint8_t i=3; i>0; i--) {
        fprintf(stderr, "%d...", i);
        SDL_Delay(1000);
    }
    fprintf(stderr, "\n");
	SDL_AudioDeviceID playback_id = SDL_OpenAudioDevice(default_playback_device_name, 0, &p_spec, &p_obtained, 0);
    fprintf(stderr, "Opening record device in ");
    for (uint8_t i=3; i>0; i--) {
        fprintf(stderr, "%d...", i);
        SDL_Delay(1000);
    }
    fprintf(stderr, "\n");

    /* This line forces mono playback on AirPods, both in SDL programs and other applications */
    SDL_AudioDeviceID record_id = SDL_OpenAudioDevice(default_record_device_name, 1, &r_spec, &r_obtained, 0);

    fprintf(stderr, "Record device opened\n");
    SDL_Delay(1000);

    fprintf(stderr, "Default record device id: %d, obtained spec channels: %d\n", record_id, r_obtained.channels);
    fprintf(stderr, "Default playback device id: %d, obtained spec channels: %d\n", playback_id, p_obtained.channels);
1 Like