const struct Hrtf *GetHrtf(ALCdevice *device) { if(device->FmtChans == DevFmtStereo) { ALuint i; for(i = 0;i < NumLoadedHrtfs;i++) { if(device->Frequency == LoadedHrtfs[i].sampleRate) return &LoadedHrtfs[i]; } if(device->Frequency == DefaultHrtf.sampleRate) return &DefaultHrtf; } ERR("Incompatible format: %s %uhz\n", DevFmtChannelsString(device->FmtChans), device->Frequency); return NULL; }
const struct Hrtf *GetHrtf(ALCdevice *device) { if(device->FmtChans == DevFmtStereo) { struct Hrtf *Hrtf = LoadedHrtfs; while(Hrtf != NULL) { if(device->Frequency == Hrtf->sampleRate) return Hrtf; Hrtf = Hrtf->next; } Hrtf = LoadHrtf(device->Frequency); if(Hrtf != NULL) return Hrtf; if(device->Frequency == DefaultHrtf.sampleRate) return &DefaultHrtf; } ERR("Incompatible format: %s %uhz\n", DevFmtChannelsString(device->FmtChans), device->Frequency); return NULL; }
static ALCenum oss_open_capture(ALCdevice *device, const ALCchar *deviceName) { int numFragmentsLogSize; int log2FragmentSize; unsigned int periods; audio_buf_info info; ALuint frameSize; int numChannels; oss_data *data; int ossFormat; int ossSpeed; char *err; if(!deviceName) deviceName = oss_device; else if(strcmp(deviceName, oss_device) != 0) return ALC_INVALID_VALUE; data = (oss_data*)calloc(1, sizeof(oss_data)); data->killNow = 0; data->fd = open(oss_capture, O_RDONLY); if(data->fd == -1) { free(data); ERR("Could not open %s: %s\n", oss_capture, strerror(errno)); return ALC_INVALID_VALUE; } switch(device->FmtType) { case DevFmtByte: ossFormat = AFMT_S8; break; case DevFmtUByte: ossFormat = AFMT_U8; break; case DevFmtShort: ossFormat = AFMT_S16_NE; break; case DevFmtUShort: case DevFmtInt: case DevFmtUInt: case DevFmtFloat: free(data); ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType)); return ALC_INVALID_VALUE; } periods = 4; numChannels = ChannelsFromDevFmt(device->FmtChans); frameSize = numChannels * BytesFromDevFmt(device->FmtType); ossSpeed = device->Frequency; log2FragmentSize = log2i(device->UpdateSize * device->NumUpdates * frameSize / periods); /* according to the OSS spec, 16 bytes are the minimum */ if (log2FragmentSize < 4) log2FragmentSize = 4; numFragmentsLogSize = (periods << 16) | log2FragmentSize; #define CHECKERR(func) if((func) < 0) { \ err = #func; \ goto err; \ } CHECKERR(ioctl(data->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize)); CHECKERR(ioctl(data->fd, SNDCTL_DSP_SETFMT, &ossFormat)); CHECKERR(ioctl(data->fd, SNDCTL_DSP_CHANNELS, &numChannels)); CHECKERR(ioctl(data->fd, SNDCTL_DSP_SPEED, &ossSpeed)); CHECKERR(ioctl(data->fd, SNDCTL_DSP_GETISPACE, &info)); if(0) { err: ERR("%s failed: %s\n", err, strerror(errno)); close(data->fd); free(data); return ALC_INVALID_VALUE; } #undef CHECKERR if((int)ChannelsFromDevFmt(device->FmtChans) != numChannels) { ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels); close(data->fd); free(data); return ALC_INVALID_VALUE; } if(!((ossFormat == AFMT_S8 && device->FmtType == DevFmtByte) || (ossFormat == AFMT_U8 && device->FmtType == DevFmtUByte) || (ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort))) { ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(device->FmtType), ossFormat); close(data->fd); free(data); return ALC_INVALID_VALUE; } data->ring = CreateRingBuffer(frameSize, device->UpdateSize * device->NumUpdates); if(!data->ring) { ERR("Ring buffer create failed\n"); close(data->fd); free(data); return ALC_OUT_OF_MEMORY; } data->data_size = info.fragsize; data->mix_data = calloc(1, data->data_size); device->ExtraData = data; data->thread = StartThread(OSSCaptureProc, device); if(data->thread == NULL) { device->ExtraData = NULL; free(data->mix_data); free(data); return ALC_OUT_OF_MEMORY; } device->szDeviceName = strdup(deviceName); return ALC_NO_ERROR; }
static ALCboolean oss_reset_playback(ALCdevice *device) { oss_data *data = (oss_data*)device->ExtraData; int numFragmentsLogSize; int log2FragmentSize; unsigned int periods; audio_buf_info info; ALuint frameSize; int numChannels; int ossFormat; int ossSpeed; char *err; switch(device->FmtType) { case DevFmtByte: ossFormat = AFMT_S8; break; case DevFmtUByte: ossFormat = AFMT_U8; break; case DevFmtUShort: case DevFmtInt: case DevFmtUInt: case DevFmtFloat: device->FmtType = DevFmtShort; /* fall-through */ case DevFmtShort: ossFormat = AFMT_S16_NE; break; } periods = device->NumUpdates; numChannels = ChannelsFromDevFmt(device->FmtChans); frameSize = numChannels * BytesFromDevFmt(device->FmtType); ossSpeed = device->Frequency; log2FragmentSize = log2i(device->UpdateSize * frameSize); /* according to the OSS spec, 16 bytes are the minimum */ if (log2FragmentSize < 4) log2FragmentSize = 4; /* Subtract one period since the temp mixing buffer counts as one. Still * need at least two on the card, though. */ if(periods > 2) periods--; numFragmentsLogSize = (periods << 16) | log2FragmentSize; #define CHECKERR(func) if((func) < 0) { \ err = #func; \ goto err; \ } /* Don't fail if SETFRAGMENT fails. We can handle just about anything * that's reported back via GETOSPACE */ ioctl(data->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize); CHECKERR(ioctl(data->fd, SNDCTL_DSP_SETFMT, &ossFormat)); CHECKERR(ioctl(data->fd, SNDCTL_DSP_CHANNELS, &numChannels)); CHECKERR(ioctl(data->fd, SNDCTL_DSP_SPEED, &ossSpeed)); CHECKERR(ioctl(data->fd, SNDCTL_DSP_GETOSPACE, &info)); if(0) { err: ERR("%s failed: %s\n", err, strerror(errno)); return ALC_FALSE; } #undef CHECKERR if((int)ChannelsFromDevFmt(device->FmtChans) != numChannels) { ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels); return ALC_FALSE; } if(!((ossFormat == AFMT_S8 && device->FmtType == DevFmtByte) || (ossFormat == AFMT_U8 && device->FmtType == DevFmtUByte) || (ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort))) { ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(device->FmtType), ossFormat); return ALC_FALSE; } device->Frequency = ossSpeed; device->UpdateSize = info.fragsize / frameSize; device->NumUpdates = info.fragments + 1; SetDefaultChannelOrder(device); return ALC_TRUE; }
static struct Hrtf *LoadHrtf(ALuint deviceRate) { const char *fnamelist = NULL; if(!ConfigValueStr(NULL, "hrtf_tables", &fnamelist)) return NULL; while(*fnamelist != '\0') { struct Hrtf *Hrtf = NULL; char fname[PATH_MAX]; ALchar magic[8]; ALuint i; FILE *f; while(isspace(*fnamelist) || *fnamelist == ',') fnamelist++; i = 0; while(*fnamelist != '\0' && *fnamelist != ',') { const char *next = strpbrk(fnamelist, "%,"); while(fnamelist != next && *fnamelist && i < sizeof(fname)) fname[i++] = *(fnamelist++); if(!next || *next == ',') break; /* *next == '%' */ next++; if(*next == 'r') { int wrote = snprintf(&fname[i], sizeof(fname)-i, "%u", deviceRate); i += minu(wrote, sizeof(fname)-i); next++; } else if(*next == '%') { if(i < sizeof(fname)) fname[i++] = '%'; next++; } else ERR("Invalid marker '%%%c'\n", *next); fnamelist = next; } i = minu(i, sizeof(fname)-1); fname[i] = '\0'; while(i > 0 && isspace(fname[i-1])) i--; fname[i] = '\0'; if(fname[0] == '\0') continue; TRACE("Loading %s...\n", fname); f = fopen(fname, "rb"); if(f == NULL) { ERR("Could not open %s\n", fname); continue; } if(fread(magic, 1, sizeof(magic), f) != sizeof(magic)) ERR("Failed to read magic marker\n"); else { if(memcmp(magic, magicMarker00, sizeof(magicMarker00)) == 0) { TRACE("Detected data set format v0\n"); Hrtf = LoadHrtf00(f, deviceRate); } else if(memcmp(magic, magicMarker01, sizeof(magicMarker01)) == 0) { TRACE("Detected data set format v1\n"); Hrtf = LoadHrtf01(f, deviceRate); } else ERR("Invalid magic marker: \"%.8s\"\n", magic); } fclose(f); f = NULL; if(Hrtf) { Hrtf->next = LoadedHrtfs; LoadedHrtfs = Hrtf; TRACE("Loaded HRTF support for format: %s %uhz\n", DevFmtChannelsString(DevFmtStereo), Hrtf->sampleRate); return Hrtf; } ERR("Failed to load %s\n", fname); } return NULL; }
static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) { AudioStreamBasicDescription requestedFormat; // The application requested format AudioStreamBasicDescription hardwareFormat; // The hardware format AudioStreamBasicDescription outputFormat; // The AudioUnit output format AURenderCallbackStruct input; ComponentDescription desc; AudioDeviceID inputDevice; UInt32 outputFrameCount; UInt32 propertySize; UInt32 enableIO; Component comp; ca_data *data; OSStatus err; desc.componentType = kAudioUnitType_Output; desc.componentSubType = kAudioUnitSubType_HALOutput; desc.componentManufacturer = kAudioUnitManufacturer_Apple; desc.componentFlags = 0; desc.componentFlagsMask = 0; // Search for component with given description comp = FindNextComponent(NULL, &desc); if(comp == NULL) { ERR("FindNextComponent failed\n"); return ALC_INVALID_VALUE; } data = calloc(1, sizeof(*data)); device->ExtraData = data; // Open the component err = OpenAComponent(comp, &data->audioUnit); if(err != noErr) { ERR("OpenAComponent failed\n"); goto error; } // Turn off AudioUnit output enableIO = 0; err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(ALuint)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); goto error; } // Turn on AudioUnit input enableIO = 1; err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(ALuint)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); goto error; } // Get the default input device propertySize = sizeof(AudioDeviceID); err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &propertySize, &inputDevice); if(err != noErr) { ERR("AudioHardwareGetProperty failed\n"); goto error; } if(inputDevice == kAudioDeviceUnknown) { ERR("No input device found\n"); goto error; } // Track the input device err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &inputDevice, sizeof(AudioDeviceID)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); goto error; } // set capture callback input.inputProc = ca_capture_callback; input.inputProcRefCon = device; err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &input, sizeof(AURenderCallbackStruct)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); goto error; } // Initialize the device err = AudioUnitInitialize(data->audioUnit); if(err != noErr) { ERR("AudioUnitInitialize failed\n"); goto error; } // Get the hardware format propertySize = sizeof(AudioStreamBasicDescription); err = AudioUnitGetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &hardwareFormat, &propertySize); if(err != noErr || propertySize != sizeof(AudioStreamBasicDescription)) { ERR("AudioUnitGetProperty failed\n"); goto error; } // Set up the requested format description switch(device->FmtType) { case DevFmtUByte: requestedFormat.mBitsPerChannel = 8; requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked; break; case DevFmtShort: requestedFormat.mBitsPerChannel = 16; requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; break; case DevFmtInt: requestedFormat.mBitsPerChannel = 32; requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; break; case DevFmtFloat: requestedFormat.mBitsPerChannel = 32; requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked; break; case DevFmtByte: case DevFmtUShort: case DevFmtUInt: ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType)); goto error; } switch(device->FmtChans) { case DevFmtMono: requestedFormat.mChannelsPerFrame = 1; break; case DevFmtStereo: requestedFormat.mChannelsPerFrame = 2; break; case DevFmtQuad: case DevFmtX51: case DevFmtX51Side: case DevFmtX61: case DevFmtX71: ERR("%s not supported\n", DevFmtChannelsString(device->FmtChans)); goto error; } requestedFormat.mBytesPerFrame = requestedFormat.mChannelsPerFrame * requestedFormat.mBitsPerChannel / 8; requestedFormat.mBytesPerPacket = requestedFormat.mBytesPerFrame; requestedFormat.mSampleRate = device->Frequency; requestedFormat.mFormatID = kAudioFormatLinearPCM; requestedFormat.mReserved = 0; requestedFormat.mFramesPerPacket = 1; // save requested format description for later use data->format = requestedFormat; data->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); // Use intermediate format for sample rate conversion (outputFormat) // Set sample rate to the same as hardware for resampling later outputFormat = requestedFormat; outputFormat.mSampleRate = hardwareFormat.mSampleRate; // Determine sample rate ratio for resampling data->sampleRateRatio = outputFormat.mSampleRate / device->Frequency; // The output format should be the requested format, but using the hardware sample rate // This is because the AudioUnit will automatically scale other properties, except for sample rate err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, (void *)&outputFormat, sizeof(outputFormat)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); goto error; } // Set the AudioUnit output format frame count outputFrameCount = device->UpdateSize * data->sampleRateRatio; err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Output, 0, &outputFrameCount, sizeof(outputFrameCount)); if(err != noErr) { ERR("AudioUnitSetProperty failed: %d\n", err); goto error; } // Set up sample converter err = AudioConverterNew(&outputFormat, &requestedFormat, &data->audioConverter); if(err != noErr) { ERR("AudioConverterNew failed: %d\n", err); goto error; } // Create a buffer for use in the resample callback data->resampleBuffer = malloc(device->UpdateSize * data->frameSize * data->sampleRateRatio); // Allocate buffer for the AudioUnit output data->bufferList = allocate_buffer_list(outputFormat.mChannelsPerFrame, device->UpdateSize * data->frameSize * data->sampleRateRatio); if(data->bufferList == NULL) goto error; data->ring = CreateRingBuffer(data->frameSize, (device->UpdateSize * data->sampleRateRatio) * device->NumUpdates); if(data->ring == NULL) goto error; al_string_copy_cstr(&device->DeviceName, deviceName); return ALC_NO_ERROR; error: DestroyRingBuffer(data->ring); free(data->resampleBuffer); destroy_buffer_list(data->bufferList); if(data->audioConverter) AudioConverterDispose(data->audioConverter); if(data->audioUnit) CloseComponent(data->audioUnit); free(data); device->ExtraData = NULL; return ALC_INVALID_VALUE; }
void InitHrtf(void) { char *fnamelist=NULL, *next=NULL; const char *val; if(ConfigValueStr(NULL, "hrtf_tables", &val)) next = fnamelist = strdup(val); while(next && *next) { const ALubyte maxDelay = SRC_HISTORY_LENGTH-1; struct Hrtf newdata; ALboolean failed; ALchar magic[9]; ALsizei i, j; char *fname; FILE *f; fname = next; next = strchr(fname, ','); if(next) { while(next != fname) { next--; if(!isspace(*next)) { *(next++) = '\0'; break; } } while(isspace(*next) || *next == ',') next++; } if(!fname[0]) continue; TRACE("Loading %s\n", fname); f = fopen(fname, "rb"); if(f == NULL) { ERR("Could not open %s\n", fname); continue; } failed = AL_FALSE; if(fread(magic, 1, sizeof(magicMarker), f) != sizeof(magicMarker)) { ERR("Failed to read magic marker\n"); failed = AL_TRUE; } else if(memcmp(magic, magicMarker, sizeof(magicMarker)) != 0) { magic[8] = 0; ERR("Invalid magic marker: \"%s\"\n", magic); failed = AL_TRUE; } if(!failed) { ALushort hrirCount, hrirSize; ALubyte evCount; newdata.sampleRate = fgetc(f); newdata.sampleRate |= fgetc(f)<<8; newdata.sampleRate |= fgetc(f)<<16; newdata.sampleRate |= fgetc(f)<<24; hrirCount = fgetc(f); hrirCount |= fgetc(f)<<8; hrirSize = fgetc(f); hrirSize |= fgetc(f)<<8; evCount = fgetc(f); if(hrirCount != HRIR_COUNT || hrirSize != HRIR_LENGTH || evCount != ELEV_COUNT) { ERR("Unsupported value: hrirCount=%d (%d), hrirSize=%d (%d), evCount=%d (%d)\n", hrirCount, HRIR_COUNT, hrirSize, HRIR_LENGTH, evCount, ELEV_COUNT); failed = AL_TRUE; } } if(!failed) { for(i = 0;i < ELEV_COUNT;i++) { ALushort offset; offset = fgetc(f); offset |= fgetc(f)<<8; if(offset != evOffset[i]) { ERR("Unsupported evOffset[%d] value: %d (%d)\n", i, offset, evOffset[i]); failed = AL_TRUE; } } } if(!failed) { for(i = 0;i < HRIR_COUNT;i++) { for(j = 0;j < HRIR_LENGTH;j++) { ALshort coeff; coeff = fgetc(f); coeff |= fgetc(f)<<8; newdata.coeffs[i][j] = coeff; } } for(i = 0;i < HRIR_COUNT;i++) { ALubyte delay; delay = fgetc(f); newdata.delays[i] = delay; if(delay > maxDelay) { ERR("Invalid delay[%d]: %d (%d)\n", i, delay, maxDelay); failed = AL_TRUE; } } if(feof(f)) { ERR("Premature end of data\n"); failed = AL_TRUE; } } fclose(f); f = NULL; if(!failed) { void *temp = realloc(LoadedHrtfs, (NumLoadedHrtfs+1)*sizeof(LoadedHrtfs[0])); if(temp != NULL) { LoadedHrtfs = temp; TRACE("Loaded HRTF support for format: %s %uhz\n", DevFmtChannelsString(DevFmtStereo), newdata.sampleRate); LoadedHrtfs[NumLoadedHrtfs++] = newdata; } } else ERR("Failed to load %s\n", fname); } free(fnamelist); fnamelist = NULL; }
static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self) { ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; audio_info_t info; ALsizei frameSize; ALsizei numChannels; AUDIO_INITINFO(&info); info.play.sample_rate = device->Frequency; if(device->FmtChans != DevFmtMono) device->FmtChans = DevFmtStereo; numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); info.play.channels = numChannels; switch(device->FmtType) { case DevFmtByte: info.play.precision = 8; info.play.encoding = AUDIO_ENCODING_LINEAR; break; case DevFmtUByte: info.play.precision = 8; info.play.encoding = AUDIO_ENCODING_LINEAR8; break; case DevFmtUShort: case DevFmtInt: case DevFmtUInt: case DevFmtFloat: device->FmtType = DevFmtShort; /* fall-through */ case DevFmtShort: info.play.precision = 16; info.play.encoding = AUDIO_ENCODING_LINEAR; break; } frameSize = numChannels * BytesFromDevFmt(device->FmtType); info.play.buffer_size = device->UpdateSize*device->NumUpdates * frameSize; if(ioctl(self->fd, AUDIO_SETINFO, &info) < 0) { ERR("ioctl failed: %s\n", strerror(errno)); return ALC_FALSE; } if(ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder) != (ALsizei)info.play.channels) { ERR("Failed to set %s, got %u channels instead\n", DevFmtChannelsString(device->FmtChans), info.play.channels); return ALC_FALSE; } if(!((info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR8 && device->FmtType == DevFmtUByte) || (info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR && device->FmtType == DevFmtByte) || (info.play.precision == 16 && info.play.encoding == AUDIO_ENCODING_LINEAR && device->FmtType == DevFmtShort) || (info.play.precision == 32 && info.play.encoding == AUDIO_ENCODING_LINEAR && device->FmtType == DevFmtInt))) { ERR("Could not set %s samples, got %d (0x%x)\n", DevFmtTypeString(device->FmtType), info.play.precision, info.play.encoding); return ALC_FALSE; } device->Frequency = info.play.sample_rate; device->UpdateSize = (info.play.buffer_size/device->NumUpdates) + 1; SetDefaultChannelOrder(device); free(self->mix_data); self->data_size = device->UpdateSize * FrameSizeFromDevFmt( device->FmtChans, device->FmtType, device->AmbiOrder ); self->mix_data = calloc(1, self->data_size); return ALC_TRUE; }
static ALCenum pa_open_playback(ALCdevice *device, const ALCchar *deviceName) { PaStreamParameters outParams; pa_data *data; PaError err; if(!deviceName) deviceName = pa_device; else if(strcmp(deviceName, pa_device) != 0) return ALC_INVALID_VALUE; data = (pa_data*)calloc(1, sizeof(pa_data)); data->update_size = device->UpdateSize; device->ExtraData = data; outParams.device = -1; if(!ConfigValueInt("port", "device", &outParams.device) || outParams.device < 0) outParams.device = Pa_GetDefaultOutputDevice(); outParams.suggestedLatency = (device->UpdateSize*device->NumUpdates) / (float)device->Frequency; outParams.hostApiSpecificStreamInfo = NULL; switch(device->FmtType) { case DevFmtByte: outParams.sampleFormat = paInt8; break; case DevFmtUByte: outParams.sampleFormat = paUInt8; break; case DevFmtUShort: device->FmtType = DevFmtShort; /* fall-through */ case DevFmtShort: outParams.sampleFormat = paInt16; break; case DevFmtFloat: outParams.sampleFormat = paFloat32; break; } outParams.channelCount = ((device->FmtChans == DevFmtMono) ? 1 : 2); SetDefaultChannelOrder(device); err = Pa_OpenStream(&data->stream, NULL, &outParams, device->Frequency, device->UpdateSize, paNoFlag, pa_callback, device); if(err != paNoError) { ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err)); device->ExtraData = NULL; free(data); return ALC_INVALID_VALUE; } device->szDeviceName = strdup(deviceName); if((ALuint)outParams.channelCount != ChannelsFromDevFmt(device->FmtChans)) { if(outParams.channelCount != 1 && outParams.channelCount != 2) { ERR("Unhandled channel count: %u\n", outParams.channelCount); Pa_CloseStream(data->stream); device->ExtraData = NULL; free(data); return ALC_INVALID_VALUE; } if((device->Flags&DEVICE_CHANNELS_REQUEST)) ERR("Failed to set %s, got %u channels instead\n", DevFmtChannelsString(device->FmtChans), outParams.channelCount); device->Flags &= ~DEVICE_CHANNELS_REQUEST; device->FmtChans = ((outParams.channelCount==1) ? DevFmtMono : DevFmtStereo); } return ALC_NO_ERROR; }
static ALCenum WinMMOpenPlayback(ALCdevice *pDevice, const ALCchar *deviceName) { WAVEFORMATEX wfexFormat; WinMMData *pData = NULL; UINT lDeviceID = 0; MMRESULT res; ALuint i = 0; // Find the Device ID matching the deviceName if valid if(!deviceName || strcmp(deviceName, woDefault) == 0) lDeviceID = WAVE_MAPPER; else { if(!PlaybackDeviceList) ProbePlaybackDevices(); for(i = 0;i < NumPlaybackDevices;i++) { if(PlaybackDeviceList[i] && strcmp(deviceName, PlaybackDeviceList[i]) == 0) { lDeviceID = i; break; } } if(i == NumPlaybackDevices) return ALC_INVALID_VALUE; } pData = calloc(1, sizeof(*pData)); if(!pData) return ALC_OUT_OF_MEMORY; pDevice->ExtraData = pData; if(pDevice->FmtChans != DevFmtMono) { if((pDevice->Flags&DEVICE_CHANNELS_REQUEST) && pDevice->FmtChans != DevFmtStereo) { ERR("Failed to set %s, got Stereo instead\n", DevFmtChannelsString(pDevice->FmtChans)); pDevice->Flags &= ~DEVICE_CHANNELS_REQUEST; } pDevice->FmtChans = DevFmtStereo; } switch(pDevice->FmtType) { case DevFmtByte: pDevice->FmtType = DevFmtUByte; break; case DevFmtUShort: pDevice->FmtType = DevFmtShort; break; case DevFmtUByte: case DevFmtShort: case DevFmtFloat: break; } retry_open: memset(&wfexFormat, 0, sizeof(WAVEFORMATEX)); wfexFormat.wFormatTag = ((pDevice->FmtType == DevFmtFloat) ? WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM); wfexFormat.nChannels = ChannelsFromDevFmt(pDevice->FmtChans); wfexFormat.wBitsPerSample = BytesFromDevFmt(pDevice->FmtType) * 8; wfexFormat.nBlockAlign = wfexFormat.wBitsPerSample * wfexFormat.nChannels / 8; wfexFormat.nSamplesPerSec = pDevice->Frequency; wfexFormat.nAvgBytesPerSec = wfexFormat.nSamplesPerSec * wfexFormat.nBlockAlign; wfexFormat.cbSize = 0; if((res=waveOutOpen(&pData->hWaveHandle.Out, lDeviceID, &wfexFormat, (DWORD_PTR)&WaveOutProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) { if(pDevice->FmtType == DevFmtFloat) { pDevice->FmtType = DevFmtShort; goto retry_open; } ERR("waveOutOpen failed: %u\n", res); goto failure; } pData->hWaveThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if(pData->hWaveThreadEvent == NULL) { ERR("CreateEvent failed: %lu\n", GetLastError()); goto failure; } pData->Frequency = pDevice->Frequency; pDevice->szDeviceName = strdup((lDeviceID==WAVE_MAPPER) ? woDefault : PlaybackDeviceList[lDeviceID]); return ALC_NO_ERROR; failure: if(pData->hWaveThreadEvent) CloseHandle(pData->hWaveThreadEvent); if(pData->hWaveHandle.Out) waveOutClose(pData->hWaveHandle.Out); free(pData); pDevice->ExtraData = NULL; return ALC_INVALID_VALUE; }
static ALCboolean alsa_reset_playback(ALCdevice *device) { alsa_data *data = (alsa_data*)device->ExtraData; snd_pcm_uframes_t periodSizeInFrames; unsigned int periodLen, bufferLen; snd_pcm_sw_params_t *sp = NULL; snd_pcm_hw_params_t *p = NULL; snd_pcm_access_t access; snd_pcm_format_t format; unsigned int periods; unsigned int rate; int allowmmap; char *err; int i; format = -1; switch(device->FmtType) { case DevFmtByte: format = SND_PCM_FORMAT_S8; break; case DevFmtUByte: format = SND_PCM_FORMAT_U8; break; case DevFmtShort: format = SND_PCM_FORMAT_S16; break; case DevFmtUShort: format = SND_PCM_FORMAT_U16; break; case DevFmtFloat: format = SND_PCM_FORMAT_FLOAT; break; } allowmmap = GetConfigValueBool("alsa", "mmap", 1); periods = device->NumUpdates; periodLen = (ALuint64)device->UpdateSize * 1000000 / device->Frequency; bufferLen = periodLen * periods; rate = device->Frequency; err = NULL; snd_pcm_hw_params_malloc(&p); if((i=snd_pcm_hw_params_any(data->pcmHandle, p)) < 0) err = "any"; /* set interleaved access */ if(i >= 0 && (!allowmmap || (i=snd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0)) { if(periods > 2) { periods--; bufferLen = periodLen * periods; } if((i=snd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) err = "set access"; } /* set format (implicitly sets sample bits) */ if(i >= 0 && (i=snd_pcm_hw_params_set_format(data->pcmHandle, p, format)) < 0) { device->FmtType = DevFmtFloat; if(format == SND_PCM_FORMAT_FLOAT || (i=snd_pcm_hw_params_set_format(data->pcmHandle, p, SND_PCM_FORMAT_FLOAT)) < 0) { device->FmtType = DevFmtShort; if(format == SND_PCM_FORMAT_S16 || (i=snd_pcm_hw_params_set_format(data->pcmHandle, p, SND_PCM_FORMAT_S16)) < 0) { device->FmtType = DevFmtUByte; if(format == SND_PCM_FORMAT_U8 || (i=snd_pcm_hw_params_set_format(data->pcmHandle, p, SND_PCM_FORMAT_U8)) < 0) err = "set format"; } } } /* set channels (implicitly sets frame bits) */ if(i >= 0 && (i=snd_pcm_hw_params_set_channels(data->pcmHandle, p, ChannelsFromDevFmt(device->FmtChans))) < 0) { if((i=snd_pcm_hw_params_set_channels(data->pcmHandle, p, 2)) < 0) { if((i=snd_pcm_hw_params_set_channels(data->pcmHandle, p, 1)) < 0) err = "set channels"; else { if((device->Flags&DEVICE_CHANNELS_REQUEST)) ERR("Failed to set %s, got Mono instead\n", DevFmtChannelsString(device->FmtChans)); device->FmtChans = DevFmtMono; } } else { if((device->Flags&DEVICE_CHANNELS_REQUEST)) ERR("Failed to set %s, got Stereo instead\n", DevFmtChannelsString(device->FmtChans)); device->FmtChans = DevFmtStereo; } device->Flags &= ~DEVICE_CHANNELS_REQUEST; } if(i >= 0 && (i=snd_pcm_hw_params_set_rate_resample(data->pcmHandle, p, 0)) < 0) { ERR("Failed to disable ALSA resampler\n"); i = 0; } /* set rate (implicitly constrains period/buffer parameters) */ if(i >= 0 && (i=snd_pcm_hw_params_set_rate_near(data->pcmHandle, p, &rate, NULL)) < 0) err = "set rate near"; /* set buffer time (implicitly constrains period/buffer parameters) */ if(i >= 0 && (i=snd_pcm_hw_params_set_buffer_time_near(data->pcmHandle, p, &bufferLen, NULL)) < 0) err = "set buffer time near"; /* set period time in frame units (implicitly sets buffer size/bytes/time and period size/bytes) */ if(i >= 0 && (i=snd_pcm_hw_params_set_period_time_near(data->pcmHandle, p, &periodLen, NULL)) < 0) err = "set period time near"; /* install and prepare hardware configuration */ if(i >= 0 && (i=snd_pcm_hw_params(data->pcmHandle, p)) < 0) err = "set params"; if(i >= 0 && (i=snd_pcm_hw_params_get_access(p, &access)) < 0) err = "get access"; if(i >= 0 && (i=snd_pcm_hw_params_get_period_size(p, &periodSizeInFrames, NULL)) < 0) err = "get period size"; if(i >= 0 && (i=snd_pcm_hw_params_get_periods(p, &periods, NULL)) < 0) err = "get periods"; if(i < 0) { ERR("%s failed: %s\n", err, snd_strerror(i)); snd_pcm_hw_params_free(p); return ALC_FALSE; } snd_pcm_hw_params_free(p); err = NULL; snd_pcm_sw_params_malloc(&sp); if((i=snd_pcm_sw_params_current(data->pcmHandle, sp)) != 0) err = "sw current"; if(i == 0 && (i=snd_pcm_sw_params_set_avail_min(data->pcmHandle, sp, periodSizeInFrames)) != 0) err = "sw set avail min"; if(i == 0 && (i=snd_pcm_sw_params(data->pcmHandle, sp)) != 0) err = "sw set params"; if(i != 0) { ERR("%s failed: %s\n", err, snd_strerror(i)); snd_pcm_sw_params_free(sp); return ALC_FALSE; } snd_pcm_sw_params_free(sp); if(device->Frequency != rate) { if((device->Flags&DEVICE_FREQUENCY_REQUEST)) ERR("Failed to set %dhz, got %dhz instead\n", device->Frequency, rate); device->Flags &= ~DEVICE_FREQUENCY_REQUEST; device->Frequency = rate; } SetDefaultChannelOrder(device); data->size = snd_pcm_frames_to_bytes(data->pcmHandle, periodSizeInFrames); if(access == SND_PCM_ACCESS_RW_INTERLEAVED) { /* Increase periods by one, since the temp buffer counts as an extra * period */ periods++; data->buffer = malloc(data->size); if(!data->buffer) { ERR("buffer malloc failed\n"); return ALC_FALSE; } device->UpdateSize = periodSizeInFrames; device->NumUpdates = periods; data->thread = StartThread(ALSANoMMapProc, device); } else { i = snd_pcm_prepare(data->pcmHandle); if(i < 0) { ERR("prepare error: %s\n", snd_strerror(i)); return ALC_FALSE; } device->UpdateSize = periodSizeInFrames; device->NumUpdates = periods; data->thread = StartThread(ALSAProc, device); } if(data->thread == NULL) { ERR("Could not create playback thread\n"); free(data->buffer); data->buffer = NULL; return ALC_FALSE; } return ALC_TRUE; }