Advertisement
Guest User

Untitled

a guest
May 26th, 2019
97
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.99 KB | None | 0 0
  1. #include <combaseapi.h>
  2. #include <mmdeviceapi.h>
  3. #include <audioclient.h>
  4.  
  5. internal
  6. struct
  7. {
  8.   B32 sound_initialized;
  9.   U32 target_frames_ahead;
  10.   U32 core_audio_buffer_size;
  11.   IAudioRenderClient *render_client;
  12.   IAudioClock *audio_clock;
  13.   WAVEFORMATEX *format;
  14.   U64 last_written_frame_number;
  15.   U32 stream_latency;
  16.   AudioBuffer buffer;
  17.   AudioFormat output_format;
  18. } CoreAudioState;
  19.  
  20. HRESULT init_device(IMMDevice *device)
  21. {
  22.   HRESULT result;
  23.  
  24.   CoreAudioState.sound_initialized = false;
  25.  
  26.   DWORD device_state;
  27.   result = device->GetState(&device_state);
  28.   if (result < 0 || device_state != DEVICE_STATE_ACTIVE)
  29.   {
  30.     return result;
  31.   }
  32.  
  33.   IID audio_client_id = __uuidof(IAudioClient); // IID_IAudioClient
  34.   IAudioClient *audio_client;
  35.   result = device->Activate(
  36.     audio_client_id,
  37.     CLSCTX_ALL,
  38.     NULL,
  39.     (void **)&audio_client);
  40.   if (result < 0)
  41.   {
  42.     return result;
  43.   }
  44.  
  45.   WAVEFORMATEX *actual_format = NULL;
  46.   result = audio_client->GetMixFormat(&actual_format);
  47.   if (result < 0)
  48.   {
  49.     return result;
  50.   }
  51.  
  52.   U32 frames_per_sec = actual_format->nSamplesPerSec;
  53.   U32 samples_per_sec = frames_per_sec * actual_format->nChannels;
  54.   U32 bytes_per_sec = samples_per_sec * (actual_format->wBitsPerSample / 8);
  55.  
  56.   // TODO: check that format is acceptable
  57.  
  58.   result = audio_client->Initialize(
  59.     AUDCLNT_SHAREMODE_SHARED,
  60.     AUDCLNT_STREAMFLAGS_RATEADJUST,
  61.     (U32)((F32)CoreAudioState.target_frames_ahead / (F32)frames_per_sec * 10000000.0f),
  62.     0,
  63.     actual_format,
  64.     NULL);
  65.   if (result < 0)
  66.   {
  67.     return result;
  68.   }
  69.  
  70.   U32 core_audio_buffer_size;
  71.   result = audio_client->GetBufferSize(&core_audio_buffer_size);
  72.   if (result < 0)
  73.   {
  74.     return result;
  75.   }
  76.  
  77.   IAudioClock *audio_clock;
  78.   IID audio_clock_id = __uuidof(IAudioClock);
  79.   result = audio_client->GetService(
  80.     audio_clock_id,
  81.     (void **)&audio_clock);
  82.   if (result < 0)
  83.   {
  84.     return result;
  85.   }
  86.  
  87.   U64 bytes_per_second;
  88.   result = audio_clock->GetFrequency(&bytes_per_second);
  89.   if (result < 0)
  90.   {
  91.      return result;
  92.   }
  93.  
  94.   if (bytes_per_second != bytes_per_sec)
  95.   {
  96.     return -1;
  97.   }
  98.  
  99.   IAudioRenderClient *render_client;
  100.   IID render_client_id = __uuidof(IAudioRenderClient);
  101.   result = audio_client->GetService(
  102.     render_client_id,
  103.     (void **)&render_client);
  104.   if (result < 0)
  105.   {
  106.     return result;
  107.   }
  108.  
  109.   REFERENCE_TIME latency; // 100ns units
  110.   result = audio_client->GetStreamLatency(&latency);
  111.   if (result < 0)
  112.   {
  113.     return result;
  114.   }
  115.  
  116.   CoreAudioState.core_audio_buffer_size = core_audio_buffer_size;
  117.   CoreAudioState.audio_clock = audio_clock;
  118.   CoreAudioState.render_client = render_client;
  119.   CoreAudioState.format = actual_format;
  120.   CoreAudioState.stream_latency = (U32)(latency * frames_per_sec / 10000000); // latency in frames instead of 100ns ticks
  121.   CoreAudioState.last_written_frame_number = 0;
  122.   CoreAudioState.target_frames_ahead = min(core_audio_buffer_size, 2 * frames_per_sec / 60);
  123.  
  124.   CoreAudioState.buffer.channel_count = actual_format->nChannels;
  125.   CoreAudioState.buffer.frames_per_second = frames_per_sec;
  126.   CoreAudioState.buffer.format = AudioFormat_F32;
  127.   CoreAudioState.output_format = AudioFormat_None;
  128.   switch (CoreAudioState.format->wFormatTag)
  129.   {
  130.     case WAVE_FORMAT_PCM:
  131.     {
  132.       S32 bits = CoreAudioState.format->wBitsPerSample;
  133.       if ( 8 == bits) CoreAudioState.output_format = AudioFormat_S8;
  134.       if (16 == bits) CoreAudioState.output_format = AudioFormat_S16;
  135.       if (24 == bits) CoreAudioState.output_format = AudioFormat_S24;
  136.       if (32 == bits) CoreAudioState.output_format = AudioFormat_S32;
  137.       if (48 == bits) CoreAudioState.output_format = AudioFormat_S48;
  138.     } break;
  139.     case WAVE_FORMAT_EXTENSIBLE:
  140.     {
  141.       WAVEFORMATEXTENSIBLE *ext = (WAVEFORMATEXTENSIBLE *)CoreAudioState.format;
  142.       GUID float_sub_format;
  143.       INIT_WAVEFORMATEX_GUID(&float_sub_format, 3);
  144.       S32 bits = CoreAudioState.format->wBitsPerSample;
  145.       if ( 8 == bits) CoreAudioState.output_format = AudioFormat_S8;
  146.       if (16 == bits) CoreAudioState.output_format = AudioFormat_S16;
  147.       if (24 == bits) CoreAudioState.output_format = AudioFormat_S24;
  148.       if (32 == bits) CoreAudioState.output_format = AudioFormat_S32;
  149.       if (48 == bits) CoreAudioState.output_format = AudioFormat_S48;
  150.       if (ext->SubFormat == float_sub_format) CoreAudioState.output_format = AudioFormat_F32;
  151.     } break;
  152.     case WAVE_FORMAT_IEEE_FLOAT:
  153.     {
  154.       if (32 == CoreAudioState.format->wBitsPerSample) CoreAudioState.output_format = AudioFormat_F32;
  155.     } break;
  156.     default:
  157.     {
  158.       fail("unhandled case");
  159.     } break;
  160.   }
  161.  
  162.   // TODO use a MemoryBlock instead of VirtualAlloc
  163.   if (CoreAudioState.buffer.interleafed_samples)
  164.   {
  165.     VirtualFree(CoreAudioState.buffer.interleafed_samples, 0, MEM_RELEASE);
  166.   }
  167.   CoreAudioState.buffer.interleafed_samples = VirtualAlloc(0, CoreAudioState.target_frames_ahead * sizeof(F32) * CoreAudioState.buffer.channel_count, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
  168.  
  169.   result = audio_client->Start();
  170.   if (result < 0)
  171.   {
  172.     return result;
  173.   }
  174.  
  175.   CoreAudioState.sound_initialized = true;
  176.   return S_OK;
  177. }
  178.  
  179. class DeviceChangeListener : IMMNotificationClient
  180. {
  181.   ULONG refs = 1;
  182.   IMMDeviceEnumerator *device_enumerator;
  183.  
  184. public:
  185.  
  186.   DeviceChangeListener(IMMDeviceEnumerator *device_enumerator)
  187.   {
  188.     this->device_enumerator = device_enumerator;
  189.   }
  190.  
  191. #pragma warning(push)
  192. #pragma warning(disable:4100)
  193.   HRESULT OnDefaultDeviceChanged(
  194.     EDataFlow flow,
  195.     ERole     role,
  196.     LPCWSTR   pwstrDefaultDeviceId)
  197.   {
  198.     HRESULT result;
  199.     if (flow == eRender && role == eConsole)
  200.     {
  201.       IMMDevice *device;
  202.       result = device_enumerator->GetDefaultAudioEndpoint(
  203.         eRender,
  204.         eConsole,
  205.         &device);
  206.       if (result < 0)
  207.       {
  208.         return result;
  209.       }
  210.       return init_device(device);
  211.     }
  212.     return S_OK;
  213.   }
  214.   HRESULT OnDeviceAdded(LPCWSTR pwstrDeviceId) {return S_OK;}
  215.   HRESULT OnDeviceRemoved(LPCWSTR pwstrDeviceId) {return S_OK;}
  216.   HRESULT OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState) {return S_OK;}
  217.   HRESULT OnPropertyValueChanged(LPCWSTR pwstrDeviceId, const PROPERTYKEY key) {return S_OK;}
  218. #pragma warning(pop)
  219.  
  220.   ULONG AddRef()
  221.   {
  222.     return InterlockedIncrement(&refs);
  223.   }
  224.  
  225.   HRESULT QueryInterface(REFIID riid, VOID **ppvInterface)
  226.   {
  227.     if (IID_IUnknown == riid || __uuidof(IMMNotificationClient) == riid)
  228.     {
  229.       AddRef();
  230.       *ppvInterface = (VOID *)this;
  231.     }
  232.     else
  233.     {
  234.       *ppvInterface = NULL;
  235.       return E_NOINTERFACE;
  236.     }
  237.     return S_OK;
  238.   }
  239.  
  240.   ULONG Release()
  241.   {
  242.     ULONG ulRef = InterlockedDecrement(&refs);
  243.     if (0 == ulRef)
  244.     {
  245.       delete this;
  246.     }
  247.     return ulRef;
  248.   }
  249. };
  250.  
  251. B32 init_coreaudio()
  252. {
  253.   HRESULT result;
  254.  
  255.   result = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  256.   if (result < 0)
  257.   {
  258.     return false;
  259.   }
  260.  
  261.   const CLSID nonsens_a = __uuidof(MMDeviceEnumerator);
  262.   const IID nonsens_b = __uuidof(IMMDeviceEnumerator);
  263.   IMMDeviceEnumerator *device_enumerator;
  264.   result = CoCreateInstance(
  265.     nonsens_a,
  266.     NULL,
  267.     CLSCTX_ALL,
  268.     nonsens_b,
  269.     (void**)&device_enumerator);
  270.   if (result < 0)
  271.   {
  272.     return false;
  273.   }
  274.  
  275.   IMMDevice *device;
  276.   result = device_enumerator->GetDefaultAudioEndpoint(
  277.     eRender,
  278.     eConsole,
  279.     &device);
  280.   if (result < 0)
  281.   {
  282.     return false;
  283.   }
  284.  
  285.   static DeviceChangeListener device_change_listener(device_enumerator); // oof
  286.  
  287.   device_enumerator->RegisterEndpointNotificationCallback(
  288.     (IMMNotificationClient *)&device_change_listener);
  289.  
  290.   return init_device(device);
  291. }
  292.  
  293. AudioBuffer *get_audio_buffer()
  294. {
  295.   HRESULT result;
  296.  
  297.   if (!CoreAudioState.sound_initialized)
  298.   {
  299.     return NULL;
  300.   }
  301.  
  302.   U64 read_cursor;
  303.   result = CoreAudioState.audio_clock->GetPosition(&read_cursor, NULL);
  304.   if (result < 0)
  305.   {
  306.     return NULL;
  307.   }
  308.  
  309.   read_cursor /= CoreAudioState.format->nChannels;
  310.   read_cursor /= CoreAudioState.format->wBitsPerSample / 8;
  311.  
  312.   S32 frames_ahead;
  313.   if (CoreAudioState.last_written_frame_number <= read_cursor)
  314.   {
  315.     CoreAudioState.last_written_frame_number = read_cursor;
  316.     frames_ahead = 0;
  317.   }
  318.   else
  319.   {
  320.     U64 diff = CoreAudioState.last_written_frame_number - read_cursor;
  321.     if (diff < CoreAudioState.core_audio_buffer_size)
  322.     {
  323.       frames_ahead = (S32) diff;
  324.     }
  325.     else
  326.     {
  327.       frames_ahead = CoreAudioState.core_audio_buffer_size;
  328.     }
  329.   }
  330.  
  331.   S32 num_frames = CoreAudioState.target_frames_ahead - frames_ahead;
  332.   CoreAudioState.buffer.frame_count = num_frames;
  333.  
  334.   return &CoreAudioState.buffer;
  335. }
  336.  
  337. B32 finalize_audio(AudioBuffer *in_buffer)
  338. {
  339.   HRESULT result;
  340.  
  341.   assert(in_buffer->channel_count == CoreAudioState.format->nChannels);
  342.  
  343.   BYTE *out_buffer;
  344.   result = CoreAudioState.render_client->GetBuffer(in_buffer->frame_count, &out_buffer);
  345.   if (result < 0)
  346.   {
  347.     return false;
  348.   }
  349.  
  350.   size_t sample_count = in_buffer->frame_count * in_buffer->channel_count;
  351.   F32 *read_cursor = (F32 *)in_buffer->interleafed_samples;
  352.  
  353.   switch (CoreAudioState.output_format)
  354.   {
  355.     case AudioFormat_S8:
  356.     {
  357.       S8 *write_cursor = (S8 *)out_buffer;
  358.       for (size_t i = 0; i < sample_count; ++i)
  359.       {
  360.         *write_cursor++ = round_F32_to_S8(*read_cursor++ * s8_max);
  361.       }
  362.     } break;
  363.     case AudioFormat_S16:
  364.     {
  365.       S16 *write_cursor = (S16 *)out_buffer;
  366.       for (size_t i = 0; i < sample_count; ++i)
  367.       {
  368.         *write_cursor++ = round_F32_to_S16(*read_cursor++ * s16_max);
  369.       }
  370.     } break;
  371.     case AudioFormat_S24:
  372.     {
  373.       U8 *write_cursor = (U8 *)out_buffer;
  374.       for (size_t i = 0; i < sample_count; ++i)
  375.       {
  376.         S32 sample = round_F32_to_S32(*read_cursor++ * s32_max);
  377.         *write_cursor++ = (U8)(sample >> 8);
  378.         *write_cursor++ = (U8)(sample >> 16);
  379.         *write_cursor++ = (U8)(sample >> 24);
  380.       }
  381.     } break;
  382.     case AudioFormat_S32:
  383.     {
  384.       S32 *write_cursor = (S32 *)out_buffer;
  385.       for (size_t i = 0; i < sample_count; ++i)
  386.       {
  387.         *write_cursor++ = round_F32_to_S32(*read_cursor++ * s32_max);
  388.       }
  389.     } break;
  390.     case AudioFormat_S48:
  391.     {
  392.       U16 *write_cursor = (U16 *)out_buffer;
  393.       for (size_t i = 0; i < sample_count; ++i)
  394.       {
  395.         S64 sample = round_F32_to_S64(*read_cursor++ * s64_max);
  396.         *write_cursor++ = (U16)(sample >> 16);
  397.         *write_cursor++ = (U16)(sample >> 32);
  398.         *write_cursor++ = (U16)(sample >> 48);
  399.       }
  400.     } break;
  401.     case AudioFormat_F32:
  402.     {
  403.       F32 *write_cursor = (F32 *)out_buffer;
  404.       for (size_t i = 0; i < sample_count; ++i)
  405.       {
  406.         *write_cursor++ = *read_cursor++;
  407.       }
  408.     } break;
  409.     default:
  410.     {
  411.       fail("unhandled case");
  412.     } break;
  413.   }
  414.  
  415.   result = CoreAudioState.render_client->ReleaseBuffer(in_buffer->frame_count, 0);
  416.   if (result < 0)
  417.   {
  418.     return false;
  419.   }
  420.   CoreAudioState.last_written_frame_number += in_buffer->frame_count;
  421.  
  422.   return true;
  423. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement