macos_audio.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. #ifdef IRON_A2
  2. #include <CoreAudio/AudioHardware.h>
  3. #include <CoreServices/CoreServices.h>
  4. #include <iron_audio.h>
  5. #include BACKEND_VIDEO_H
  6. #include <iron_system.h>
  7. #include <stdio.h>
  8. static iron_internal_video_sound_stream_t *video = NULL;
  9. void macPlayVideoSoundStream(iron_internal_video_sound_stream_t *v) {
  10. video = v;
  11. }
  12. void macStopVideoSoundStream(void) {
  13. video = NULL;
  14. }
  15. static void affirm(OSStatus err) {
  16. if (err != kAudioHardwareNoError) {
  17. iron_error("Error: %i\n", err);
  18. }
  19. }
  20. static bool initialized;
  21. static bool soundPlaying;
  22. static AudioDeviceID device;
  23. static UInt32 deviceBufferSize;
  24. static UInt32 size;
  25. static AudioStreamBasicDescription deviceFormat;
  26. static AudioObjectPropertyAddress address;
  27. static AudioDeviceIOProcID theIOProcID = NULL;
  28. static iron_a2_buffer_t a2_buffer;
  29. static uint32_t samples_per_second = 44100;
  30. uint32_t iron_a2_samples_per_second(void) {
  31. return samples_per_second;
  32. }
  33. static void copySample(void *buffer) {
  34. float left_value = *(float *)&a2_buffer.channels[0][a2_buffer.read_location];
  35. float right_value = *(float *)&a2_buffer.channels[1][a2_buffer.read_location];
  36. a2_buffer.read_location += 1;
  37. if (a2_buffer.read_location >= a2_buffer.data_size) {
  38. a2_buffer.read_location = 0;
  39. }
  40. ((float *)buffer)[0] = left_value;
  41. ((float *)buffer)[1] = right_value;
  42. }
  43. static OSStatus appIOProc(AudioDeviceID inDevice, const AudioTimeStamp *inNow, const AudioBufferList *inInputData, const AudioTimeStamp *inInputTime,
  44. AudioBufferList *outOutputData, const AudioTimeStamp *inOutputTime, void *userdata) {
  45. affirm(AudioObjectGetPropertyData(device, &address, 0, NULL, &size, &deviceFormat));
  46. if (samples_per_second != (int)deviceFormat.mSampleRate) {
  47. samples_per_second = (int)deviceFormat.mSampleRate;
  48. iron_a2_internal_sample_rate_callback();
  49. }
  50. int num_frames = deviceBufferSize / deviceFormat.mBytesPerFrame;
  51. iron_a2_internal_callback(&a2_buffer, num_frames);
  52. float *output = (float *)outOutputData->mBuffers[0].mData;
  53. for (int i = 0; i < num_frames; ++i) {
  54. copySample(output);
  55. output += 2;
  56. }
  57. return kAudioHardwareNoError;
  58. }
  59. static bool initialized = false;
  60. void iron_a2_init(void) {
  61. if (initialized) {
  62. return;
  63. }
  64. iron_a2_internal_init();
  65. initialized = true;
  66. a2_buffer.read_location = 0;
  67. a2_buffer.write_location = 0;
  68. a2_buffer.data_size = 128 * 1024;
  69. a2_buffer.channel_count = 2;
  70. a2_buffer.channels[0] = (float *)malloc(a2_buffer.data_size * sizeof(float));
  71. a2_buffer.channels[1] = (float *)malloc(a2_buffer.data_size * sizeof(float));
  72. device = kAudioDeviceUnknown;
  73. initialized = false;
  74. size = sizeof(AudioDeviceID);
  75. address.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
  76. address.mScope = kAudioObjectPropertyScopeGlobal;
  77. address.mElement = kAudioObjectPropertyElementMaster;
  78. affirm(AudioObjectGetPropertyData(kAudioObjectSystemObject, &address, 0, NULL, &size, &device));
  79. size = sizeof(UInt32);
  80. address.mSelector = kAudioDevicePropertyBufferSize;
  81. address.mScope = kAudioDevicePropertyScopeOutput;
  82. affirm(AudioObjectGetPropertyData(device, &address, 0, NULL, &size, &deviceBufferSize));
  83. iron_log("deviceBufferSize = %i\n", deviceBufferSize);
  84. size = sizeof(AudioStreamBasicDescription);
  85. address.mSelector = kAudioDevicePropertyStreamFormat;
  86. address.mScope = kAudioDevicePropertyScopeOutput;
  87. affirm(AudioObjectGetPropertyData(device, &address, 0, NULL, &size, &deviceFormat));
  88. if (deviceFormat.mFormatID != kAudioFormatLinearPCM) {
  89. iron_error("mFormatID != kAudioFormatLinearPCM\n");
  90. return;
  91. }
  92. if (!(deviceFormat.mFormatFlags & kLinearPCMFormatFlagIsFloat)) {
  93. iron_error("Only works with float format.\n");
  94. return;
  95. }
  96. if (samples_per_second != (int)deviceFormat.mSampleRate) {
  97. samples_per_second = (int)deviceFormat.mSampleRate;
  98. iron_a2_internal_sample_rate_callback();
  99. }
  100. initialized = true;
  101. iron_log("mSampleRate = %g\n", deviceFormat.mSampleRate);
  102. iron_log("mFormatFlags = %08X\n", (unsigned int)deviceFormat.mFormatFlags);
  103. iron_log("mBytesPerPacket = %d\n", (unsigned int)deviceFormat.mBytesPerPacket);
  104. iron_log("mFramesPerPacket = %d\n", (unsigned int)deviceFormat.mFramesPerPacket);
  105. iron_log("mChannelsPerFrame = %d\n", (unsigned int)deviceFormat.mChannelsPerFrame);
  106. iron_log("mBytesPerFrame = %d\n", (unsigned int)deviceFormat.mBytesPerFrame);
  107. iron_log("mBitsPerChannel = %d\n", (unsigned int)deviceFormat.mBitsPerChannel);
  108. if (soundPlaying)
  109. return;
  110. affirm(AudioDeviceCreateIOProcID(device, appIOProc, NULL, &theIOProcID));
  111. affirm(AudioDeviceStart(device, theIOProcID));
  112. soundPlaying = true;
  113. }
  114. void iron_a2_update(void) {}
  115. void iron_a2_shutdown(void) {
  116. if (!initialized)
  117. return;
  118. if (!soundPlaying)
  119. return;
  120. affirm(AudioDeviceStop(device, theIOProcID));
  121. affirm(AudioDeviceDestroyIOProcID(device, theIOProcID));
  122. soundPlaying = false;
  123. }
  124. #endif