ref: 295a330c6831453e5b8f4553fe7ee594efd00f32
dir: /src/ft2_audioselector.c/
// for finding memory leaks in debug mode with Visual Studio #if defined _DEBUG && defined _MSC_VER #include <crtdbg.h> #endif #include <stdio.h> #include <stdint.h> #include "ft2_header.h" #include "ft2_config.h" #include "ft2_audio.h" #include "ft2_gui.h" #include "ft2_mouse.h" #include "ft2_audioselector.h" #include "ft2_structs.h" enum { INPUT_DEVICE = 0, OUTPUT_DEVICE = 1 }; #define MAX_DEV_STR_LEN 256 // hide POSIX warnings #ifdef _MSC_VER #pragma warning(disable: 4996) #endif static char *getReasonableAudioDevice(int32_t iscapture) // can and will return NULL { int32_t numAudioDevs = SDL_GetNumAudioDevices(iscapture); if (numAudioDevs == 0 || numAudioDevs > 1) return NULL; // we don't know which audio output device is the default device const char *devName = SDL_GetAudioDeviceName(0, iscapture); if (devName == NULL) return NULL; return strdup(devName); } char *getAudioOutputDeviceFromConfig(void) { bool audioDeviceRead = false; char *devString = NULL; FILE *f = UNICHAR_FOPEN(editor.audioDevConfigFileLocationU, "r"); if (f != NULL) { devString = (char *)malloc(MAX_DEV_STR_LEN+1); if (devString == NULL) { fclose(f); return NULL; // out of memory } devString[0] = '\0'; fgets(devString, MAX_DEV_STR_LEN, f); fclose(f); const int32_t devStringLen = (int32_t)strlen(devString); if (devStringLen > 0) { if (devString[devStringLen-1] == '\n') devString[devStringLen-1] = '\0'; if (!(devStringLen == 1 && devString[0] == ' ')) // space only = no device audioDeviceRead = true; } } if (!audioDeviceRead) { if (devString != NULL) free(devString); devString = getReasonableAudioDevice(OUTPUT_DEVICE); } // SDL_OpenAudioDevice() doesn't seem to like an empty audio device string if (devString != NULL && devString[0] == '\0') { free(devString); return NULL; } return devString; } char *getAudioInputDeviceFromConfig(void) { bool audioDeviceRead = false; char *devString = NULL; FILE *f = UNICHAR_FOPEN(editor.audioDevConfigFileLocationU, "r"); if (f != NULL) { devString = (char *)malloc(MAX_DEV_STR_LEN+1); if (devString == NULL) { fclose(f); return NULL; // out of memory } devString[0] = '\0'; fgets(devString, MAX_DEV_STR_LEN, f); // skip first line (we want the input device) fgets(devString, MAX_DEV_STR_LEN, f); fclose(f); const int32_t devStringLen = (int32_t)strlen(devString); if (devStringLen > 0) { if (devString[devStringLen-1] == '\n') devString[devStringLen-1] = '\0'; if (!(devStringLen == 1 && devString[0] == ' ')) // space only = no device audioDeviceRead = true; } } if (!audioDeviceRead) { if (devString != NULL) free(devString); devString = getReasonableAudioDevice(INPUT_DEVICE); } // SDL_OpenAudioDevice() doesn't seem to like an empty audio device string if (devString != NULL && devString[0] == '\0') { free(devString); return NULL; } return devString; } bool saveAudioDevicesToConfig(const char *outputDevice, const char *inputDevice) { FILE *f = UNICHAR_FOPEN(editor.audioDevConfigFileLocationU, "w"); if (f == NULL) return false; if (outputDevice != NULL) fputs(outputDevice, f); else fputc(' ', f); fputc('\n', f); if (inputDevice != NULL) fputs(inputDevice, f); else fputc(' ', f); fclose(f); return true; } void drawAudioOutputList(void) { clearRect(114, 18, AUDIO_SELECTORS_BOX_WIDTH, 66); if (audio.outputDeviceNum == 0) { textOut(114, 18, PAL_FORGRND, "No audio output devices found!"); return; } for (int32_t i = 0; i < 6; i++) { const int32_t deviceEntry = getScrollBarPos(SB_AUDIO_OUTPUT_SCROLL) + i; if (deviceEntry < audio.outputDeviceNum) { if (audio.outputDeviceNames[deviceEntry] == NULL) continue; const uint16_t y = 18 + (uint16_t)(i * 11); if (audio.currOutputDevice != NULL) { if (strcmp(audio.currOutputDevice, audio.outputDeviceNames[deviceEntry]) == 0) fillRect(114, y, AUDIO_SELECTORS_BOX_WIDTH, 10, PAL_BOXSLCT); // selection background color } char *tmpString = utf8ToCp437(audio.outputDeviceNames[deviceEntry], true); if (tmpString != NULL) { textOutClipX(114, y, PAL_FORGRND, tmpString, 114 + AUDIO_SELECTORS_BOX_WIDTH); free(tmpString); } } } } void drawAudioInputList(void) { clearRect(114, 105, AUDIO_SELECTORS_BOX_WIDTH, 44); if (audio.inputDeviceNum == 0) { textOut(114, 105, PAL_FORGRND, "No audio input devices found!"); return; } for (int32_t i = 0; i < 4; i++) { const int32_t deviceEntry = getScrollBarPos(SB_AUDIO_INPUT_SCROLL) + i; if (deviceEntry < audio.inputDeviceNum) { if (audio.inputDeviceNames[deviceEntry] == NULL) continue; const uint16_t y = 105 + (uint16_t)(i * 11); if (audio.currInputDevice != NULL) { if (strcmp(audio.currInputDevice, audio.inputDeviceNames[deviceEntry]) == 0) fillRect(114, y, AUDIO_SELECTORS_BOX_WIDTH, 10, PAL_BOXSLCT); // selection background color } char *tmpString = utf8ToCp437(audio.inputDeviceNames[deviceEntry], true); if (tmpString != NULL) { textOutClipX(114, y, PAL_FORGRND, tmpString, 114 + AUDIO_SELECTORS_BOX_WIDTH); free(tmpString); } } } } bool testAudioDeviceListsMouseDown(void) { if (!ui.configScreenShown || editor.currConfigScreen != CONFIG_SCREEN_AUDIO) return false; const int32_t mx = mouse.x; const int32_t my = mouse.y; if (my < 18 || my > 149 || mx < 114 || mx >= 114+AUDIO_SELECTORS_BOX_WIDTH) return false; if (my < 84) { // output device list const int32_t deviceNum = (int32_t)scrollBars[SB_AUDIO_OUTPUT_SCROLL].pos + ((my - 18) / 11); if (audio.outputDeviceNum <= 0 || deviceNum >= audio.outputDeviceNum) return true; char *devString = audio.outputDeviceNames[deviceNum]; if (devString != NULL && (audio.currOutputDevice == NULL || strcmp(audio.currOutputDevice, devString) != 0)) { if (audio.currOutputDevice != NULL) free(audio.currOutputDevice); const uint32_t devStringLen = (uint32_t)strlen(devString); audio.currOutputDevice = (char *)malloc(devStringLen+1); if (audio.currOutputDevice == NULL) return true; audio.currOutputDevice[0] = '\0'; if (devStringLen > 0) strcpy(audio.currOutputDevice, devString); if (!setNewAudioSettings()) okBox(0, "System message", "Couldn't open audio output device!", NULL); else drawAudioOutputList(); } return true; } else if (my >= 105) { // input device list const int32_t deviceNum = (int32_t)scrollBars[SB_AUDIO_INPUT_SCROLL].pos + ((my - 105) / 11); if (audio.inputDeviceNum <= 0 || deviceNum >= audio.inputDeviceNum) return true; char *devString = audio.inputDeviceNames[deviceNum]; if (devString != NULL && (audio.currInputDevice == NULL || strcmp(audio.currInputDevice, devString) != 0)) { if (audio.currInputDevice != NULL) free(audio.currInputDevice); const uint32_t devStringLen = (uint32_t)strlen(devString); audio.currInputDevice = (char *)malloc(devStringLen+1); if (audio.currInputDevice == NULL) return true; audio.currInputDevice[0] = '\0'; if (devStringLen > 0) strcpy(audio.currInputDevice, devString); drawAudioInputList(); } return true; } return false; } void freeAudioDeviceLists(void) { for (int32_t i = 0; i < MAX_AUDIO_DEVICES; i++) { if (audio.outputDeviceNames[i] != NULL) { free(audio.outputDeviceNames[i]); audio.outputDeviceNames[i] = NULL; } if (audio.inputDeviceNames[i] != NULL) { free(audio.inputDeviceNames[i]); audio.inputDeviceNames[i] = NULL; } audio.outputDeviceNum = 0; audio.inputDeviceNum = 0; } } void freeAudioDeviceSelectorBuffers(void) { if (editor.audioDevConfigFileLocationU != NULL) { free(editor.audioDevConfigFileLocationU); editor.audioDevConfigFileLocationU = NULL; } if (audio.currOutputDevice != NULL) { free(audio.currOutputDevice); audio.currOutputDevice = NULL; } if (audio.currInputDevice != NULL) { free(audio.currInputDevice); audio.currInputDevice = NULL; } if (audio.lastWorkingAudioDeviceName != NULL) { free(audio.lastWorkingAudioDeviceName); audio.lastWorkingAudioDeviceName = NULL; } freeAudioDeviceLists(); } void setToDefaultAudioOutputDevice(void) { if (audio.currOutputDevice != NULL) { free(audio.currOutputDevice); audio.currOutputDevice = NULL; } /* If we have more than one device, we can't know which one ** is the default (and thus not get its device name). ** SDL2 ought to have a function for this! */ if (SDL_GetNumAudioDevices(false) == 1) { const char *devName = SDL_GetAudioDeviceName(0, false); if (devName != NULL) audio.currOutputDevice = strdup(devName); } } void setToDefaultAudioInputDevice(void) { if (audio.currInputDevice != NULL) { free(audio.currInputDevice); audio.currInputDevice = NULL; } /* If we have more than one device, we can't know which one ** is the default (and thus not get its device name). ** SDL2 ought to have a function for this! */ if (SDL_GetNumAudioDevices(true) == 1) { const char *devName = SDL_GetAudioDeviceName(0, true); if (devName != NULL) audio.currInputDevice = strdup(devName); } } void rescanAudioDevices(void) { const bool listShown = (ui.configScreenShown && editor.currConfigScreen == CONFIG_SCREEN_AUDIO); freeAudioDeviceLists(); // GET AUDIO OUTPUT DEVICES audio.outputDeviceNum = SDL_GetNumAudioDevices(false); if (audio.outputDeviceNum > MAX_AUDIO_DEVICES) audio.outputDeviceNum = MAX_AUDIO_DEVICES; for (int32_t i = 0; i < audio.outputDeviceNum; i++) { const char *deviceName = SDL_GetAudioDeviceName(i, false); if (deviceName == NULL) { audio.outputDeviceNum--; // hide device continue; } const uint32_t stringLen = (uint32_t)strlen(deviceName); audio.outputDeviceNames[i] = (char *)malloc(stringLen + 1); if (audio.outputDeviceNames[i] == NULL) break; if (stringLen > 0) strcpy(audio.outputDeviceNames[i], deviceName); } // GET AUDIO INPUT DEVICES audio.inputDeviceNum = SDL_GetNumAudioDevices(true); if (audio.inputDeviceNum > MAX_AUDIO_DEVICES) audio.inputDeviceNum = MAX_AUDIO_DEVICES; for (int32_t i = 0; i < audio.inputDeviceNum; i++) { const char *deviceName = SDL_GetAudioDeviceName(i, true); if (deviceName == NULL) { audio.inputDeviceNum--; // hide device continue; } const uint32_t stringLen = (uint32_t)strlen(deviceName); audio.inputDeviceNames[i] = (char *)malloc(stringLen + 1); if (audio.inputDeviceNames[i] == NULL) break; if (stringLen > 0) strcpy(audio.inputDeviceNames[i], deviceName); } setScrollBarEnd(SB_AUDIO_OUTPUT_SCROLL, audio.outputDeviceNum); setScrollBarPos(SB_AUDIO_OUTPUT_SCROLL, 0, false); setScrollBarEnd(SB_AUDIO_INPUT_SCROLL, audio.inputDeviceNum); setScrollBarPos(SB_AUDIO_INPUT_SCROLL, 0, false); // DRAW LISTS if (listShown) { drawAudioOutputList(); drawAudioInputList(); drawScrollBar(SB_AUDIO_OUTPUT_SCROLL); drawScrollBar(SB_AUDIO_INPUT_SCROLL); } } void scrollAudInputDevListUp(void) { scrollBarScrollUp(SB_AUDIO_INPUT_SCROLL, 1); } void scrollAudInputDevListDown(void) { scrollBarScrollDown(SB_AUDIO_INPUT_SCROLL, 1); } void scrollAudOutputDevListUp(void) { scrollBarScrollUp(SB_AUDIO_OUTPUT_SCROLL, 1); } void scrollAudOutputDevListDown(void) { scrollBarScrollDown(SB_AUDIO_OUTPUT_SCROLL, 1); } void sbAudOutputSetPos(uint32_t pos) { if (ui.configScreenShown && (editor.currConfigScreen == CONFIG_SCREEN_AUDIO)) drawAudioOutputList(); (void)pos; } void sbAudInputSetPos(uint32_t pos) { if (ui.configScreenShown && (editor.currConfigScreen == CONFIG_SCREEN_AUDIO)) drawAudioInputList(); (void)pos; }