bool audio::orchestra::api::Core::open(uint32_t _device, audio::orchestra::mode _mode, uint32_t _channels, uint32_t _firstChannel, uint32_t _sampleRate, audio::format _format, uint32_t *_bufferSize, const audio::orchestra::StreamOptions& _options) { // Get device ID uint32_t nDevices = getDeviceCount(); if (nDevices == 0) { // This should not happen because a check is made before this function is called. ATA_ERROR("no devices found!"); return false; } if (_device >= nDevices) { // This should not happen because a check is made before this function is called. ATA_ERROR("device ID is invalid!"); return false; } AudioDeviceID deviceList[ nDevices/2 ]; uint32_t dataSize = sizeof(AudioDeviceID) * nDevices/2; AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &property, 0, nullptr, &dataSize, (void *) &deviceList); if (result != noErr) { ATA_ERROR("OS-X system error getting device IDs."); return false; } AudioDeviceID id = deviceList[ _device/2 ]; // Setup for stream mode. bool isInput = false; if (_mode == audio::orchestra::mode_input) { isInput = true; property.mScope = kAudioDevicePropertyScopeInput; } else { property.mScope = kAudioDevicePropertyScopeOutput; } // Get the stream "configuration". AudioBufferList *bufferList = nil; dataSize = 0; property.mSelector = kAudioDevicePropertyStreamConfiguration; result = AudioObjectGetPropertyDataSize(id, &property, 0, nullptr, &dataSize); if ( result != noErr || dataSize == 0) { ATA_ERROR("system error (" << getErrorCode(result) << ") getting stream configuration info for device (" << _device << ")."); return false; } // Allocate the AudioBufferList. bufferList = (AudioBufferList *) malloc(dataSize); if (bufferList == nullptr) { ATA_ERROR("memory error allocating AudioBufferList."); return false; } result = AudioObjectGetPropertyData(id, &property, 0, nullptr, &dataSize, bufferList); if ( result != noErr || dataSize == 0) { ATA_ERROR("system error (" << getErrorCode(result) << ") getting stream configuration for device (" << _device << ")."); return false; } // Search for one or more streams that contain the desired number of // channels. CoreAudio devices can have an arbitrary number of // streams and each stream can have an arbitrary number of channels. // For each stream, a single buffer of interleaved samples is // provided. orchestra prefers the use of one stream of interleaved // data or multiple consecutive single-channel streams. However, we // now support multiple consecutive multi-channel streams of // interleaved data as well. uint32_t iStream, offsetCounter = _firstChannel; uint32_t nStreams = bufferList->mNumberBuffers; bool monoMode = false; bool foundStream = false; // First check that the device supports the requested number of // channels. uint32_t deviceChannels = 0; for (iStream=0; iStream<nStreams; iStream++) { deviceChannels += bufferList->mBuffers[iStream].mNumberChannels; } if (deviceChannels < (_channels + _firstChannel)) { free(bufferList); ATA_ERROR("the device (" << _device << ") does not support the requested channel count."); return false; } // Look for a single stream meeting our needs. uint32_t firstStream, streamCount = 1, streamChannels = 0, channelOffset = 0; for (iStream=0; iStream<nStreams; iStream++) { streamChannels = bufferList->mBuffers[iStream].mNumberChannels; if (streamChannels >= _channels + offsetCounter) { firstStream = iStream; channelOffset = offsetCounter; foundStream = true; break; } if (streamChannels > offsetCounter) { break; } offsetCounter -= streamChannels; } // If we didn't find a single stream above, then we should be able // to meet the channel specification with multiple streams. if (foundStream == false) { monoMode = true; offsetCounter = _firstChannel; for (iStream=0; iStream<nStreams; iStream++) { streamChannels = bufferList->mBuffers[iStream].mNumberChannels; if (streamChannels > offsetCounter) { break; } offsetCounter -= streamChannels; } firstStream = iStream; channelOffset = offsetCounter; int32_t channelCounter = _channels + offsetCounter - streamChannels; if (streamChannels > 1) { monoMode = false; } while (channelCounter > 0) { streamChannels = bufferList->mBuffers[++iStream].mNumberChannels; if (streamChannels > 1) { monoMode = false; } channelCounter -= streamChannels; streamCount++; } } free(bufferList); // Determine the buffer size. AudioValueRange bufferRange; dataSize = sizeof(AudioValueRange); property.mSelector = kAudioDevicePropertyBufferFrameSizeRange; result = AudioObjectGetPropertyData(id, &property, 0, nullptr, &dataSize, &bufferRange); if (result != noErr) { ATA_ERROR("system error (" << getErrorCode(result) << ") getting buffer size range for device (" << _device << ")."); return false; } if (bufferRange.mMinimum > *_bufferSize) { *_bufferSize = (uint64_t) bufferRange.mMinimum; } else if (bufferRange.mMaximum < *_bufferSize) { *_bufferSize = (uint64_t) bufferRange.mMaximum; } if (_options.flags.m_minimizeLatency == true) { *_bufferSize = (uint64_t) bufferRange.mMinimum; } // Set the buffer size. For multiple streams, I'm assuming we only // need to make this setting for the master channel. uint32_t theSize = (uint32_t) *_bufferSize; dataSize = sizeof(uint32_t); property.mSelector = kAudioDevicePropertyBufferFrameSize; result = AudioObjectSetPropertyData(id, &property, 0, nullptr, dataSize, &theSize); if (result != noErr) { ATA_ERROR("system error (" << getErrorCode(result) << ") setting the buffer size for device (" << _device << ")."); return false; } // If attempting to setup a duplex stream, the bufferSize parameter // MUST be the same in both directions! *_bufferSize = theSize; if ( m_mode == audio::orchestra::mode_output && _mode == audio::orchestra::mode_input && *_bufferSize != m_bufferSize) { ATA_ERROR("system error setting buffer size for duplex stream on device (" << _device << ")."); return false; } m_bufferSize = *_bufferSize; m_nBuffers = 1; // Check and if necessary, change the sample rate for the device. double nominalRate; dataSize = sizeof(double); property.mSelector = kAudioDevicePropertyNominalSampleRate; result = AudioObjectGetPropertyData(id, &property, 0, nullptr, &dataSize, &nominalRate); if (result != noErr) { ATA_ERROR("system error (" << getErrorCode(result) << ") getting current sample rate."); return false; } // Only change the sample rate if off by more than 1 Hz. if (fabs(nominalRate - (double)_sampleRate) > 1.0) { // Set a property listener for the sample rate change double reportedRate = 0.0; AudioObjectPropertyAddress tmp = { kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; result = AudioObjectAddPropertyListener(id, &tmp, &rateListener, (void *) &reportedRate); if (result != noErr) { ATA_ERROR("system error (" << getErrorCode(result) << ") setting sample rate property listener for device (" << _device << ")."); return false; } nominalRate = (double) _sampleRate; result = AudioObjectSetPropertyData(id, &property, 0, nullptr, dataSize, &nominalRate); if (result != noErr) { ATA_ERROR("system error (" << getErrorCode(result) << ") setting sample rate for device (" << _device << ")."); return false; } // Now wait until the reported nominal rate is what we just set. uint32_t microCounter = 0; while (reportedRate != nominalRate) { microCounter += 5000; if (microCounter > 5000000) { break; } std::this_thread::sleep_for(std::chrono::milliseconds(5)); } // Remove the property listener. AudioObjectRemovePropertyListener(id, &tmp, &rateListener, (void *) &reportedRate); if (microCounter > 5000000) { ATA_ERROR("timeout waiting for sample rate update for device (" << _device << ")."); return false; } } // Now set the stream format for all streams. Also, check the // physical format of the device and change that if necessary. AudioStreamBasicDescription description; dataSize = sizeof(AudioStreamBasicDescription); property.mSelector = kAudioStreamPropertyVirtualFormat; result = AudioObjectGetPropertyData(id, &property, 0, nullptr, &dataSize, &description); if (result != noErr) { ATA_ERROR("system error (" << getErrorCode(result) << ") getting stream format for device (" << _device << ")."); return false; } // Set the sample rate and data format id. However, only make the // change if the sample rate is not within 1.0 of the desired // rate and the format is not linear pcm. bool updateFormat = false; if (fabs(description.mSampleRate - (double)_sampleRate) > 1.0) { description.mSampleRate = (double) _sampleRate; updateFormat = true; } if (description.mFormatID != kAudioFormatLinearPCM) { description.mFormatID = kAudioFormatLinearPCM; updateFormat = true; } if (updateFormat) { result = AudioObjectSetPropertyData(id, &property, 0, nullptr, dataSize, &description); if (result != noErr) { ATA_ERROR("system error (" << getErrorCode(result) << ") setting sample rate or data format for device (" << _device << ")."); return false; } } // Now check the physical format. property.mSelector = kAudioStreamPropertyPhysicalFormat; result = AudioObjectGetPropertyData(id, &property, 0, nullptr, &dataSize, &description); if (result != noErr) { ATA_ERROR("system error (" << getErrorCode(result) << ") getting stream physical format for device (" << _device << ")."); return false; } //std::cout << "Current physical stream format:" << std::endl; //std::cout << " mBitsPerChan = " << description.mBitsPerChannel << std::endl; //std::cout << " aligned high = " << (description.mFormatFlags & kAudioFormatFlagIsAlignedHigh) << ", isPacked = " << (description.mFormatFlags & kAudioFormatFlagIsPacked) << std::endl; //std::cout << " bytesPerFrame = " << description.mBytesPerFrame << std::endl; //std::cout << " sample rate = " << description.mSampleRate << std::endl; if ( description.mFormatID != kAudioFormatLinearPCM || description.mBitsPerChannel < 16) { description.mFormatID = kAudioFormatLinearPCM; //description.mSampleRate = (double) sampleRate; AudioStreamBasicDescription testDescription = description; uint32_t formatFlags; // We'll try higher bit rates first and then work our way down. std::vector< std::pair<uint32_t, uint32_t> > physicalFormats; formatFlags = (description.mFormatFlags | kLinearPCMFormatFlagIsFloat) & ~kLinearPCMFormatFlagIsSignedInteger; physicalFormats.push_back(std::pair<float, uint32_t>(32, formatFlags)); formatFlags = (description.mFormatFlags | kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked) & ~kLinearPCMFormatFlagIsFloat; physicalFormats.push_back(std::pair<float, uint32_t>(32, formatFlags)); physicalFormats.push_back(std::pair<float, uint32_t>(24, formatFlags)); // 24-bit packed formatFlags &= ~(kAudioFormatFlagIsPacked | kAudioFormatFlagIsAlignedHigh); physicalFormats.push_back(std::pair<float, uint32_t>(24.2, formatFlags)); // 24-bit in 4 bytes, aligned low formatFlags |= kAudioFormatFlagIsAlignedHigh; physicalFormats.push_back(std::pair<float, uint32_t>(24.4, formatFlags)); // 24-bit in 4 bytes, aligned high formatFlags = (description.mFormatFlags | kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked) & ~kLinearPCMFormatFlagIsFloat; physicalFormats.push_back(std::pair<float, uint32_t>(16, formatFlags)); physicalFormats.push_back(std::pair<float, uint32_t>(8, formatFlags)); bool setPhysicalFormat = false; for(uint32_t i=0; i<physicalFormats.size(); i++) { testDescription = description; testDescription.mBitsPerChannel = (uint32_t) physicalFormats[i].first; testDescription.mFormatFlags = physicalFormats[i].second; if ( (24 == (uint32_t)physicalFormats[i].first) && ~(physicalFormats[i].second & kAudioFormatFlagIsPacked)) { testDescription.mBytesPerFrame = 4 * testDescription.mChannelsPerFrame; } else { testDescription.mBytesPerFrame = testDescription.mBitsPerChannel/8 * testDescription.mChannelsPerFrame; } testDescription.mBytesPerPacket = testDescription.mBytesPerFrame * testDescription.mFramesPerPacket; result = AudioObjectSetPropertyData(id, &property, 0, nullptr, dataSize, &testDescription); if (result == noErr) { setPhysicalFormat = true; //std::cout << "Updated physical stream format:" << std::endl; //std::cout << " mBitsPerChan = " << testDescription.mBitsPerChannel << std::endl; //std::cout << " aligned high = " << (testDescription.mFormatFlags & kAudioFormatFlagIsAlignedHigh) << ", isPacked = " << (testDescription.mFormatFlags & kAudioFormatFlagIsPacked) << std::endl; //std::cout << " bytesPerFrame = " << testDescription.mBytesPerFrame << std::endl; //std::cout << " sample rate = " << testDescription.mSampleRate << std::endl; break; } } if (!setPhysicalFormat) { ATA_ERROR("system error (" << getErrorCode(result) << ") setting physical data format for device (" << _device << ")."); return false; } } // done setting virtual/physical formats. // Get the stream / device latency. uint32_t latency; dataSize = sizeof(uint32_t); property.mSelector = kAudioDevicePropertyLatency; if (AudioObjectHasProperty(id, &property) == true) { result = AudioObjectGetPropertyData(id, &property, 0, nullptr, &dataSize, &latency); if (result == kAudioHardwareNoError) { m_latency[ _mode ] = latency; } else { ATA_ERROR("system error (" << getErrorCode(result) << ") getting device latency for device (" << _device << ")."); return false; } } // Byte-swapping: According to AudioHardware.h, the stream data will // always be presented in native-endian format, so we should never // need to byte swap. m_doByteSwap[modeToIdTable(_mode)] = false; // From the CoreAudio documentation, PCM data must be supplied as // 32-bit floats. m_userFormat = _format; m_deviceFormat[modeToIdTable(_mode)] = audio::format_float; if (streamCount == 1) { m_nDeviceChannels[modeToIdTable(_mode)] = description.mChannelsPerFrame; } else { // multiple streams m_nDeviceChannels[modeToIdTable(_mode)] = _channels; } m_nUserChannels[modeToIdTable(_mode)] = _channels; m_channelOffset[modeToIdTable(_mode)] = channelOffset; // offset within a CoreAudio stream m_deviceInterleaved[modeToIdTable(_mode)] = true; if (monoMode == true) { m_deviceInterleaved[modeToIdTable(_mode)] = false; } // Set flags for buffer conversion. m_doConvertBuffer[modeToIdTable(_mode)] = false; if (m_userFormat != m_deviceFormat[modeToIdTable(_mode)]) { m_doConvertBuffer[modeToIdTable(_mode)] = true; } if (m_nUserChannels[modeToIdTable(_mode)] < m_nDeviceChannels[modeToIdTable(_mode)]) { m_doConvertBuffer[modeToIdTable(_mode)] = true; } if (streamCount == 1) { if ( m_nUserChannels[modeToIdTable(_mode)] > 1 && m_deviceInterleaved[modeToIdTable(_mode)] == false) { m_doConvertBuffer[modeToIdTable(_mode)] = true; } } else if (monoMode) { m_doConvertBuffer[modeToIdTable(_mode)] = true; } m_private->iStream[modeToIdTable(_mode)] = firstStream; m_private->nStreams[modeToIdTable(_mode)] = streamCount; m_private->id[modeToIdTable(_mode)] = id; // Allocate necessary internal buffers. uint64_t bufferBytes; bufferBytes = m_nUserChannels[modeToIdTable(_mode)] * *_bufferSize * audio::getFormatBytes(m_userFormat); // m_userBuffer[modeToIdTable(_mode)] = (char *) calloc(bufferBytes, 1); m_userBuffer[modeToIdTable(_mode)].resize(bufferBytes, 0); if (m_userBuffer[modeToIdTable(_mode)].size() == 0) { ATA_ERROR("error allocating user buffer memory."); goto error; } // If possible, we will make use of the CoreAudio stream buffers as // "device buffers". However, we can't do this if using multiple // streams. if ( m_doConvertBuffer[modeToIdTable(_mode)] && m_private->nStreams[modeToIdTable(_mode)] > 1) { bool makeBuffer = true; bufferBytes = m_nDeviceChannels[modeToIdTable(_mode)] * audio::getFormatBytes(m_deviceFormat[modeToIdTable(_mode)]); if (_mode == audio::orchestra::mode_input) { if ( m_mode == audio::orchestra::mode_output && m_deviceBuffer) { uint64_t bytesOut = m_nDeviceChannels[0] * audio::getFormatBytes(m_deviceFormat[0]); if (bufferBytes <= bytesOut) { makeBuffer = false; } } } if (makeBuffer) { bufferBytes *= *_bufferSize; if (m_deviceBuffer) { free(m_deviceBuffer); m_deviceBuffer = nullptr; } m_deviceBuffer = (char *) calloc(bufferBytes, 1); if (m_deviceBuffer == nullptr) { ATA_ERROR("error allocating device buffer memory."); goto error; } } } m_sampleRate = _sampleRate; m_device[modeToIdTable(_mode)] = _device; m_state = audio::orchestra::state::stopped; ATA_VERBOSE("Set state as stopped"); // Setup the buffer conversion information structure. if (m_doConvertBuffer[modeToIdTable(_mode)]) { if (streamCount > 1) { setConvertInfo(_mode, 0); } else { setConvertInfo(_mode, channelOffset); } } if ( _mode == audio::orchestra::mode_input && m_mode == audio::orchestra::mode_output && m_device[0] == _device) { // Only one callback procedure per device. m_mode = audio::orchestra::mode_duplex; } else { #if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5) result = AudioDeviceCreateIOProcID(id, &audio::orchestra::api::Core::callbackEvent, this, &m_private->procId[modeToIdTable(_mode)]); #else // deprecated in favor of AudioDeviceCreateIOProcID() result = AudioDeviceAddIOProc(id, &audio::orchestra::api::Core::callbackEvent, this); #endif if (result != noErr) { ATA_ERROR("system error setting callback for device (" << _device << ")."); goto error; } if ( m_mode == audio::orchestra::mode_output && _mode == audio::orchestra::mode_input) { m_mode = audio::orchestra::mode_duplex; } else { m_mode = _mode; } } // Setup the device property listener for over/underload. property.mSelector = kAudioDeviceProcessorOverload; result = AudioObjectAddPropertyListener(id, &property, &audio::orchestra::api::Core::xrunListener, this); return true; error: m_userBuffer[0].clear(); m_userBuffer[1].clear(); if (m_deviceBuffer) { free(m_deviceBuffer); m_deviceBuffer = 0; } m_state = audio::orchestra::state::closed; ATA_VERBOSE("Set state as closed"); return false; }
tbool CDeviceCoreAudio::Start() { OSErr err1 = AudioDeviceAddIOProc(mAudioDeviceID, HALIOProc, (void*)this); OSErr err2 = AudioDeviceStart(mAudioDeviceID, HALIOProc); return ((err1 == 0) && (err2 == 0)); } // Start
static GVBool gviHardwareStartCapture(GVDevice device) { GVIHardwareData * data = (GVIHardwareData *)device->m_data; OSStatus result; // now capturing data->m_capturing = GVTrue; // add the IO proc result = AudioDeviceAddIOProc((AudioDeviceID)device->m_deviceID, gviHardwareCaptureIOProc, device); if(result != noErr) { data->m_capturing = GVFalse; return GVFalse; } // start it result = AudioDeviceStart((AudioDeviceID)device->m_deviceID, gviHardwareCaptureIOProc); if(result != noErr) { data->m_capturing = GVFalse; return GVFalse; } return GVTrue; }
static GVBool gviHardwareStartPlayback(GVDevice device) { GVIHardwareData * data = (GVIHardwareData *)device->m_data; OSStatus result; // now playing data->m_playing = GVTrue; // reset the playback clock data->m_playbackClock = 0; // add the IO proc result = AudioDeviceAddIOProc((AudioDeviceID)device->m_deviceID, gviHardwarePlaybackIOProc, device); if(result != noErr) { data->m_playing = GVFalse; return GVFalse; } // start it result = AudioDeviceStart((AudioDeviceID)device->m_deviceID, gviHardwarePlaybackIOProc); if(result != noErr) { data->m_playing = GVFalse; return GVFalse; } return GVTrue; }
// ------------------------------------------------------ // Name: AUDIO_Init_Driver() // Desc: Init the audio driver int AUDIO_Init_Driver(void (*Mixer)(Uint8 *, Uint32)) { AUDIO_Mixer = Mixer; AUDIO_Device = kAudioDeviceUnknown; Amount = sizeof(AudioDeviceID); if(AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &Amount, (void *) &AUDIO_Device) == noErr) { if(AudioDeviceAddIOProc(AUDIO_Device, AUDIO_Callback, NULL) == noErr) { return(AUDIO_Create_Sound_Buffer(AUDIO_Milliseconds)); } #if !defined(__STAND_ALONE__) && !defined(__WINAMP__) else { Message_Error("Error while calling AudioDeviceAddIOProc()"); } #endif } #if !defined(__STAND_ALONE__) && !defined(__WINAMP__) else { Message_Error("Error while calling AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice)"); } #endif return(FALSE); }
static OSStatus AudioDeviceCreateIOProcID(AudioDeviceID dev, AudioDeviceIOProc proc, void *data, AudioDeviceIOProcID *procid) { *procid = proc; return AudioDeviceAddIOProc(dev, proc, data); }
static void set_input_callback(AudioDeviceID id, AudioDeviceIOProc cbk, void *data) { OSStatus err = noErr; err = AudioDeviceAddIOProc(id, cbk, data); if (err != noErr) { DBG_DYNA_AUDIO_DRV("!!CoreAudio: can't set input callback\n"); } }
static au_instance_t *audiounits_create_recorder(SEXP source, float rate, int chs, int flags) { UInt32 propsize=0; OSStatus err; au_instance_t *ap = (au_instance_t*) calloc(sizeof(au_instance_t), 1); ap->source = source; ap->sample_rate = rate; ap->done = NO; ap->position = 0; ap->length = LENGTH(source); ap->stereo = (chs == 2) ? YES : NO; propsize = sizeof(ap->inDev); err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &propsize, &ap->inDev); if (err) { free(ap); Rf_error("unable to find default audio input (%08x)", err); } propsize = sizeof(ap->fmtIn); err = AudioDeviceGetProperty(ap->inDev, 0, YES, kAudioDevicePropertyStreamFormat, &propsize, &ap->fmtIn); if (err) { free(ap); Rf_error("unable to retrieve audio input format (%08x)", err); } /* Rprintf(" recording format: %f, chs: %d, fpp: %d, bpp: %d, bpf: %d, flags: %x\n", ap->fmtIn.mSampleRate, ap->fmtIn.mChannelsPerFrame, ap->fmtIn.mFramesPerPacket, ap->fmtIn.mBytesPerPacket, ap->fmtIn.mBytesPerFrame, ap->fmtIn.mFormatFlags); */ ap->srFrac = 1.0; if (ap->fmtIn.mSampleRate != ap->sample_rate) ap->srFrac = ap->sample_rate / ap->fmtIn.mSampleRate; ap->srRun = 0.0; #if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED>=MAC_OS_X_VERSION_10_5) err = AudioDeviceCreateIOProcID(ap->inDev, inputRenderProc, ap, &ap->inIOProcID ); #else err = AudioDeviceAddIOProc(ap->inDev, inputRenderProc, ap); #endif if (err) { free(ap); Rf_error("unable to register recording callback (%08x)", err); } R_PreserveObject(ap->source); Rf_setAttrib(ap->source, Rf_install("rate"), Rf_ScalarInteger(rate)); /* we adjust the rate */ Rf_setAttrib(ap->source, Rf_install("bits"), Rf_ScalarInteger(16)); /* we say it's 16 because we don't know - float is always 32-bit */ Rf_setAttrib(ap->source, Rf_install("class"), Rf_mkString("audioSample")); if (ap->stereo) { SEXP dim = Rf_allocVector(INTSXP, 2); INTEGER(dim)[0] = 2; INTEGER(dim)[1] = LENGTH(ap->source) / 2; Rf_setAttrib(ap->source, R_DimSymbol, dim); } return ap; }
bool CCoreAudioDevice::AddIOProc(AudioDeviceIOProc ioProc, void* pCallbackData) { if (!m_DeviceId || m_IoProc) // Only one IOProc at a time return false; OSStatus ret = AudioDeviceAddIOProc(m_DeviceId, ioProc, pCallbackData); if (ret) { CLog::Log(LOGERROR, "CCoreAudioDevice::Stop: Unable to add IOProc. Error = 0x%08x (%4.4s).", ret, CONVERT_OSSTATUS(ret)); return false; } m_IoProc = ioProc; CLog::Log(LOGDEBUG, "CCoreAudioDevice::AddIOProc: IOProc set for device 0x%04x", m_DeviceId); return true; }
static int ca_init (void) { UInt32 sz; char device_name[128]; sz = sizeof(device_id); if (AudioHardwareGetProperty (kAudioHardwarePropertyDefaultOutputDevice, &sz, &device_id)) { return -1; } sz = sizeof (device_name); if (AudioDeviceGetProperty (device_id, 1, 0, kAudioDevicePropertyDeviceName, &sz, device_name)) { return -1; } sz = sizeof (default_format); if (AudioDeviceGetProperty (device_id, 0, 0, kAudioDevicePropertyStreamFormat, &sz, &default_format)) { return -1; } UInt32 bufsize = 4096; sz = sizeof (bufsize); if (AudioDeviceSetProperty(device_id, NULL, 0, 0, kAudioDevicePropertyBufferFrameSize, sz, &bufsize)) { fprintf (stderr, "Failed to set buffer size\n"); } if (ca_apply_format ()) { return -1; } if (AudioDeviceAddIOProc (device_id, ca_buffer_callback, NULL)) { return -1; } if (AudioDeviceAddPropertyListener (device_id, 0, 0, kAudioDevicePropertyStreamFormat, ca_fmtchanged, NULL)) { return -1; } ca_fmtchanged(0, 0, 0, kAudioDevicePropertyStreamFormat, NULL); state = OUTPUT_STATE_STOPPED; return 0; }
// start the device attached to the stream. // static int Stream_startSema(Stream *s, int semaIndex) { AudioDeviceIOProc ioProc= s->direction ? ioProcInput : ioProcOutput; debugf("stream %p[%d] startSema: %d\n", s, s->direction, semaIndex); s->semaphore= semaIndex; // can be zero if (checkError(AudioDeviceAddIOProc(s->id, ioProc, (void *)s), "Add", "ioProcOut")) return 0; if (checkError(AudioDeviceStart(s->id, ioProc), "DeviceStart", "ioProcOut")) { AudioDeviceRemoveIOProc(s->id, ioProc); return 0; } debugf("stream %p[%d] running\n", s, s->direction); return 1; }
bool start (AudioIODeviceCallback* cb) { if (! started) { callback = nullptr; if (deviceID != 0) { #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 if (OK (AudioDeviceAddIOProc (deviceID, audioIOProc, this))) #else if (OK (AudioDeviceCreateIOProcID (deviceID, audioIOProc, this, &audioProcID))) #endif { if (OK (AudioDeviceStart (deviceID, audioIOProc))) { started = true; } else { #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 OK (AudioDeviceRemoveIOProc (deviceID, audioIOProc)); #else OK (AudioDeviceDestroyIOProcID (deviceID, audioProcID)); audioProcID = 0; #endif } } } } if (started) { const ScopedLock sl (callbackLock); callback = cb; } return started && (inputDevice == nullptr || inputDevice->start (cb)); }
int audev_init_device(char *wantdevname, long ratewanted, int verbose, extraopt_t *extra) { int bx, res; OSStatus status; int channels; long rate; long fragsize; int listdevices = FALSE; AudioDeviceID wantdevid; AudioDeviceID wantedaudev; extraopt_t *opt; UInt32 propsize; UInt32 bytecount; struct AudioStreamBasicDescription streamdesc; #define LEN_DEVICE_NAME 128 char devicename[LEN_DEVICE_NAME]; if (verbose) { printf("Boodler: OSX CoreAudio sound driver.\n"); } fragsize = 32768; bufcount = 6; for (opt=extra; opt->key; opt++) { if (!strcmp(opt->key, "buffersize") && opt->val) { fragsize = atol(opt->val); } else if (!strcmp(opt->key, "buffercount") && opt->val) { bufcount = atoi(opt->val); } else if (!strcmp(opt->key, "listdevices")) { listdevices = TRUE; } } if (bufcount < 2) bufcount = 2; if (audevice != kAudioDeviceUnknown) { fprintf(stderr, "Sound device is already open.\n"); return FALSE; } wantedaudev = kAudioDeviceUnknown; /* If the given device name is a string representation of an integer, work out the integer. */ wantdevid = kAudioDeviceUnknown; if (wantdevname) { char *endptr = NULL; wantdevid = strtol(wantdevname, &endptr, 10); if (!endptr || endptr == wantdevname || (*endptr != '\0')) wantdevid = kAudioDeviceUnknown; } if (listdevices || wantdevname) { int ix, jx; int device_count; #define LEN_DEVICE_LIST 16 AudioDeviceID devicelist[LEN_DEVICE_LIST]; propsize = LEN_DEVICE_LIST * sizeof(AudioDeviceID); status = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &propsize, devicelist); if (status) { fprintf(stderr, "Could not get list of audio devices.\n"); return FALSE; } device_count = propsize / sizeof(AudioDeviceID); for (ix=0; ix<device_count; ix++) { AudioDeviceID tmpaudev = devicelist[ix]; /* Determine if this is an output device. */ status = AudioDeviceGetPropertyInfo(tmpaudev, 0, 0, kAudioDevicePropertyStreamConfiguration, &propsize, NULL); if (status) { fprintf(stderr, "Could not get audio property info.\n"); return FALSE; } AudioBufferList *buflist = (AudioBufferList *)malloc(propsize); status = AudioDeviceGetProperty(tmpaudev, 0, 0, kAudioDevicePropertyStreamConfiguration, &propsize, buflist); if (status) { fprintf(stderr, "Could not get audio property info.\n"); return FALSE; } int hasoutput = FALSE; for (jx=0; jx<buflist->mNumberBuffers; jx++) { if (buflist->mBuffers[jx].mNumberChannels > 0) { hasoutput = TRUE; } } free(buflist); buflist = NULL; if (!hasoutput) { /* skip this device. */ continue; } /* Determine the device name. */ propsize = LEN_DEVICE_NAME * sizeof(char); status = AudioDeviceGetProperty(tmpaudev, 1, 0, kAudioDevicePropertyDeviceName, &propsize, devicename); if (status) { fprintf(stderr, "Could not get audio device name.\n"); return FALSE; } if (listdevices) printf("Found device ID %d: \"%s\".\n", (int)tmpaudev, devicename); /* Check if the desired name matches (a prefix of) the device name. */ if (wantdevname && !strncmp(wantdevname, devicename, strlen(wantdevname))) { wantedaudev = tmpaudev; } /* Check if the int version of the desired name matches the device ID. */ if (wantdevid != kAudioDeviceUnknown && wantdevid == tmpaudev) { wantedaudev = tmpaudev; } } } if (wantdevname) { audevice = wantedaudev; } else { propsize = sizeof(audevice); status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &propsize, &audevice); if (status) { fprintf(stderr, "Could not get audio default device.\n"); return FALSE; } } if (audevice == kAudioDeviceUnknown) { fprintf(stderr, "Audio default device is unknown.\n"); return FALSE; } propsize = LEN_DEVICE_NAME * sizeof(char); status = AudioDeviceGetProperty(audevice, 1, 0, kAudioDevicePropertyDeviceName, &propsize, devicename); if (status) { fprintf(stderr, "Could not get audio device name.\n"); return FALSE; } if (verbose) { printf("Got device ID %d: \"%s\".\n", (int)audevice, devicename); } if (ratewanted) { memset(&streamdesc, 0, sizeof(streamdesc)); streamdesc.mSampleRate = ratewanted; propsize = sizeof(streamdesc); status = AudioDeviceSetProperty(audevice, NULL, 0, 0, kAudioDevicePropertyStreamFormatMatch, propsize, &streamdesc); if (status) { fprintf(stderr, "Could not set sample rate; continuing.\n"); } } { bytecount = fragsize; propsize = sizeof(bytecount); status = AudioDeviceSetProperty(audevice, NULL, 0, 0, kAudioDevicePropertyBufferSize, propsize, &bytecount); if (status) { fprintf(stderr, "Could not set buffer size; continuing.\n"); } } propsize = sizeof(struct AudioStreamBasicDescription); status = AudioDeviceGetProperty(audevice, 1, 0, kAudioDevicePropertyStreamFormat, &propsize, &streamdesc); if (status) { fprintf(stderr, "Could not get audio device description.\n"); return FALSE; } rate = streamdesc.mSampleRate; if (streamdesc.mFormatID != kAudioFormatLinearPCM) { fprintf(stderr, "Audio device format is not LinearPCM; exiting.\n"); return FALSE; } if (streamdesc.mChannelsPerFrame != 2) { fprintf(stderr, "Audio device is not stereo; exiting.\n"); return FALSE; } channels = 2; if (!(streamdesc.mFormatFlags & kLinearPCMFormatFlagIsFloat)) { fprintf(stderr, "Audio device is not floating-point; exiting.\n"); return FALSE; } propsize = sizeof(bytecount); status = AudioDeviceGetProperty(audevice, 1, 0, kAudioDevicePropertyBufferSize, &propsize, &bytecount); if (status) { fprintf(stderr, "Could not get audio device buffer size.\n"); return FALSE; } fragsize = bytecount; if (verbose) { printf("%ld bytes per buffer.\n", fragsize); } if (verbose) { printf("%d buffers in queue.\n", bufcount); } /* Everything's figured out. */ sound_rate = rate; sound_channels = channels; sound_buffersize = fragsize; framesperbuf = sound_buffersize / (sizeof(float) * sound_channels); samplesperbuf = framesperbuf * sound_channels; if (verbose) { printf("%ld frames (%ld samples) per buffer.\n", framesperbuf, samplesperbuf); printf("%ld frames per second.\n", rate); } emptying = 0; filling = 0; bailing = FALSE; valbuffer = (long *)malloc(sizeof(long) * samplesperbuf); if (!valbuffer) { fprintf(stderr, "Unable to allocate sound buffer.\n"); return FALSE; } memset(valbuffer, 0, sizeof(long) * samplesperbuf); rawbuffer = (buffer_t *)malloc(sizeof(buffer_t) * bufcount); memset(rawbuffer, 0, sizeof(buffer_t) * bufcount); for (bx=0; bx<bufcount; bx++) { buffer_t *buffer = &rawbuffer[bx]; buffer->full = FALSE; buffer->buf = (float *)malloc(sound_buffersize); if (!buffer->buf) { fprintf(stderr, "Unable to allocate sound buffer.\n"); /* free stuff */ return FALSE; } memset(buffer->buf, 0, sound_buffersize); res = pthread_mutex_init(&buffer->mutex, NULL); if (res) { fprintf(stderr, "Unable to init mutex.\n"); /* free stuff */ return FALSE; } res = pthread_cond_init(&buffer->cond, NULL); if (res) { fprintf(stderr, "Unable to init cond.\n"); /* free stuff */ return FALSE; } } /* AudioDeviceAddIOProc is deprecated as of OSX 10.5. Use the osxaq driver instead. */ status = AudioDeviceAddIOProc(audevice, PlaybackIOProc, (void *)1); if (status) { fprintf(stderr, "Could not add IOProc to device.\n"); return FALSE; } started = FALSE; return TRUE; }
/*return value == 0 sucess == -1 fails */ static int open_output(void) { OSStatus err = 0; //no err UInt32 count, bufferSize; AudioDeviceID device = kAudioDeviceUnknown; AudioStreamBasicDescription format; // get the default output device for the HAL count = sizeof(globals.device); // it is required to pass the size of the data to be returned err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &count, (void *) &device); if (err != 0) goto Bail; // get the buffersize that the default device uses for IO count = sizeof(globals.deviceBufferSize); // it is required to pass the size of the data to be returned err = AudioDeviceGetProperty(device, 0, 0, kAudioDevicePropertyBufferSize, &count, &bufferSize); if (err != 0) goto Bail; if( globals.deviceBufferSize>BUFLEN ){ fprintf(stderr, "globals.deviceBufferSize NG: %ld\n", globals.deviceBufferSize); exit(1); } // get a description of the data format used by the default device count = sizeof(globals.deviceFormat); // it is required to pass the size of the data to be returned err = AudioDeviceGetProperty(device, 0, 0, kAudioDevicePropertyStreamFormat, &count, &format); if (err != 0) goto Bail; FailWithAction(format.mFormatID != kAudioFormatLinearPCM, err = -1, Bail); // bail if the format is not linear pcm // everything is ok so fill in these globals globals.device = device; globals.deviceBufferSize = bufferSize; globals.deviceFormat = format; init_variable(); err = AudioDeviceAddIOProc(globals.device, appIOProc, 0 ); // setup our device with an IO proc if (err != 0) goto Bail; globals.deviceFormat.mSampleRate = dpm.rate; #if 0 globals.deviceFormat.mFormatFlags = kLinearPCMFormatFlagIsBigEndian | kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsSignedInteger; globals.deviceFormat.mBytesPerPacket = 4; globals.deviceFormat.mBytesPerFrame = 4; globals.deviceFormat.mBitsPerChannel = 0x10; err = AudioDeviceSetProperty(device, &inWhen, 0, 0, kAudioDevicePropertyStreamFormat, count, &globals.deviceFormat); if (err != 0) goto Bail; #endif #if 0 fprintf(stderr, "deviceBufferSize = %d\n", globals.deviceBufferSize); fprintf(stderr, "mSampleRate = %g\n", globals.deviceFormat.mSampleRate); fprintf(stderr, "mFormatID = 0x%08x\n", globals.deviceFormat.mFormatID); fprintf(stderr, "mFormatFlags = 0x%08x\n", globals.deviceFormat.mFormatFlags); fprintf(stderr, "mBytesPerPacket = 0x%08x\n", globals.deviceFormat.mBytesPerPacket); fprintf(stderr, "mBytesPerFrame = 0x%08x\n", globals.deviceFormat.mBytesPerFrame); fprintf(stderr, "mBitsPerChannel = 0x%08x\n", globals.deviceFormat.mBitsPerChannel); #endif Bail: return (err); }
void AudioThruEngine::Start() { if (mRunning) return; if (!mInputDevice.Valid() || !mOutputDevice.Valid()) { //printf("invalid device\n"); return; } // $$$ should do some checks on the format/sample rate matching if (mInputDevice.mFormat.mSampleRate != mOutputDevice.mFormat.mSampleRate) { if (MatchSampleRate(false)) { printf("Error - sample rate mismatch: %f / %f\n", mInputDevice.mFormat.mSampleRate, mOutputDevice.mFormat.mSampleRate); return; } } /*if (mInputDevice.mFormat.mChannelsPerFrame != mOutputDevice.mFormat.mChannelsPerFrame || mInputDevice.mFormat.mBytesPerFrame != mOutputDevice.mFormat.mBytesPerFrame) { printf("Error - format mismatch: %ld / %ld channels, %ld / %ld bytes per frame\n", mInputDevice.mFormat.mChannelsPerFrame, mOutputDevice.mFormat.mChannelsPerFrame, mInputDevice.mFormat.mBytesPerFrame, mOutputDevice.mFormat.mBytesPerFrame); return; }*/ //mErrorMessage[0] = '\0'; mInputBuffer->Allocate(mInputDevice.mFormat.mBytesPerFrame, UInt32(kSecondsInRingBuffer * mInputDevice.mFormat.mSampleRate)); mSampleRate = mInputDevice.mFormat.mSampleRate; mWorkBuf = new Byte[mInputDevice.mBufferSizeFrames * mInputDevice.mFormat.mBytesPerFrame]; memset(mWorkBuf, 0, mInputDevice.mBufferSizeFrames * mInputDevice.mFormat.mBytesPerFrame); mRunning = true; #if USE_AUDIODEVICEREAD UInt32 streamListSize; verify_noerr (AudioDeviceGetPropertyInfo(gInputDevice, 0, true, kAudioDevicePropertyStreams, &streamListSize, NULL)); UInt32 nInputStreams = streamListSize / sizeof(AudioStreamID); propsize = offsetof(AudioBufferList, mBuffers[nInputStreams]); gInputIOBuffer = (AudioBufferList *)malloc(propsize); verify_noerr (AudioDeviceGetProperty(gInputDevice, 0, true, kAudioDevicePropertyStreamConfiguration, &propsize, gInputIOBuffer)); gInputIOBuffer->mBuffers[0].mData = malloc(gInputIOBuffer->mBuffers[0].mDataByteSize); verify_noerr (AudioDeviceSetProperty(gInputDevice, NULL, 0, true, kAudioDevicePropertyRegisterBufferList, propsize, gInputIOBuffer)); #endif mInputProcState = kStarting; mOutputProcState = kStarting; verify_noerr (AudioDeviceAddIOProc(mInputDevice.mID, InputIOProc, this)); verify_noerr (AudioDeviceStart(mInputDevice.mID, InputIOProc)); if (mInputDevice.CountChannels() == 2) mOutputIOProc = OutputIOProc; else mOutputIOProc = OutputIOProc16; verify_noerr (AudioDeviceAddIOProc(mOutputDevice.mID, mOutputIOProc, this)); verify_noerr (AudioDeviceStart(mOutputDevice.mID, mOutputIOProc)); // UInt32 propsize = sizeof(UInt32); // UInt32 isAlreadyRunning; // err = (AudioDeviceGetProperty(mOutputDevice.mID, 0, false, kAudioDevicePropertyDeviceIsRunning, &propsize, &isAlreadyRunning)); // if (isAlreadyRunning) // mOutputProcState = kRunning; // else while (mInputProcState != kRunning || mOutputProcState != kRunning) usleep(1000); // usleep(12000); ComputeThruOffset(); }
int audio_output_open(void) { UInt32 size; /* Obtain the audio device ID */ size = sizeof adid; if (AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice, &size, &adid) != 0 || adid == kAudioDeviceUnknown) goto error; /* Adjust the stream format */ size = sizeof afmt; if (AudioDeviceGetProperty(adid, 0, false, kAudioDevicePropertyStreamFormat, &size, &afmt) != 0 || afmt.mFormatID != kAudioFormatLinearPCM) goto error; /* To be set on the first run */ afmt.mSampleRate = 0; afmt.mChannelsPerFrame = 0; afmt.mBytesPerFrame = afmt.mChannelsPerFrame * sizeof (float); afmt.mBytesPerPacket = afmt.mBytesPerFrame * afmt.mFramesPerPacket; /* Decide what buffer size to use */ size = sizeof abuflen; abuflen = 32768; AudioDeviceSetProperty(adid, 0, 0, false, kAudioDevicePropertyBufferSize, size, &abuflen); if (AudioDeviceGetProperty(adid, 0, false, kAudioDevicePropertyBufferSize, &size, &abuflen) != 0) goto error; #ifdef BUILD_VOLUME /* Store the audio channels */ size = sizeof achans; AudioDeviceGetProperty(adid, 0, false, kAudioDevicePropertyPreferredChannelsForStereo, &size, &achans); #endif /* BUILD_VOLUME */ /* The buffer size reported is in floats */ abuflen /= sizeof(float); abufnew = g_malloc(abuflen * sizeof(int16_t)); abufcur = g_malloc(abuflen * sizeof(int16_t)); /* Locking down the buffer length */ abuflock = g_mutex_new(); abufdrained = g_cond_new(); /* Add our own I/O handling routine */ #ifdef MAC_OS_X_VERSION_10_5 if (AudioDeviceCreateIOProcID(adid, audio_output_ioproc, NULL, &aprocid) != 0) #else /* !MAC_OS_X_VERSION_10_5 */ if (AudioDeviceAddIOProc(adid, audio_output_ioproc, NULL) != 0) #endif /* MAC_OS_X_VERSION_10_5 */ goto error; return (0); error: g_printerr("%s\n", _("Cannot open the audio device.")); return (-1); }
void audio_init_input () { unsigned long size, indev, buflen; AudioStreamBasicDescription info; /* Get default input device id. */ size = sizeof (indev); if (AudioHardwareGetProperty (kAudioHardwarePropertyDefaultInputDevice, &size, &indev) != 0 || indev == kAudioDeviceUnknown) { fprintf (stderr, "audio: cannot get input device\n"); exit (-1); } #if 0 /* Get input format. */ size = sizeof (info); if (AudioDeviceGetProperty (indev, 0, true, kAudioDevicePropertyStreamFormat, &size, &info) != 0) { fprintf (stderr, "audio: cannot get input stream format\n"); exit (-1); } printf ("Format: id %08lx, flags %lx\n", info.mFormatID, info.mFormatFlags); printf ("Frames per packet: %ld\n", info.mFramesPerPacket); printf ("Channels per frame: %ld\n", info.mChannelsPerFrame); printf ("Bytes per packet: %ld\n", info.mBytesPerPacket); printf ("Bytes per frame: %ld\n", info.mBytesPerFrame); printf ("Bits per channel: %ld\n", info.mBitsPerChannel); printf ("Sample rate: %g\n", info.mSampleRate); #endif /* Set required input format. */ info.mFormatID = kAudioFormatLinearPCM; info.mFormatFlags = kLinearPCMFormatFlagIsBigEndian | kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsFloat; info.mSampleRate = 44100; info.mChannelsPerFrame = 2; /* stereo */ info.mFramesPerPacket = 1; info.mBitsPerChannel = 8 * sizeof (float); info.mBytesPerPacket = info.mBitsPerChannel / 8 * info.mChannelsPerFrame; info.mBytesPerFrame = info.mBytesPerPacket / info.mFramesPerPacket; size = sizeof (info); if (AudioDeviceSetProperty (indev, 0, 0, true, kAudioDevicePropertyStreamFormat, size, &info) != 0) { fprintf (stderr, "audio: cannot setup input stream format\n"); exit (-1); } /* Set buffer length. */ size = sizeof (buflen); buflen = info.mBytesPerPacket * 2048; if (AudioDeviceSetProperty (indev, 0, 0, true, kAudioDevicePropertyBufferSize, size, &buflen) != 0) { fprintf (stderr, "audio: cannot set buffer length\n"); exit (-1); } /* Get buffer length. */ size = sizeof (buflen); if (AudioDeviceGetProperty (indev, 0, true, kAudioDevicePropertyBufferSize, &size, &buflen) != 0) { fprintf (stderr, "audio: cannot get buffer length\n"); exit (-1); } printf ("Buffer length: %ld bytes\n", buflen); /* Set the IO proc that CoreAudio will call when it needs data */ if (AudioDeviceAddIOProc (indev, audio_callback, 0) != 0) { fprintf (stderr, "audio: cannot add i/o procedure\n"); exit (-1); } /* Start callback */ if (AudioDeviceStart (indev, audio_callback) != 0) { fprintf (stderr, "audio: cannot start device\n"); exit (-1); } }
int macosx_audio_open(audio_desc_t ad, audio_format* ifmt, audio_format *ofmt) { OSStatus err = noErr; UInt32 propertySize; Boolean writable; obtained_ = false; add = ad; //dev[0] = devices[ad]; UNUSED(ofmt); // Get the default input device ID. err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDefaultInputDevice, &propertySize, &writable); if (err != noErr) { return 0; } err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &propertySize, &(devices[ad].inputDeviceID_)); if (err != noErr) { debug_msg("error kAudioHardwarePropertyDefaultInputDevice"); return 0; } if (devices[ad].inputDeviceID_ == kAudioDeviceUnknown) { debug_msg("error kAudioDeviceUnknown"); return 0; } // Get the input stream description. err = AudioDeviceGetPropertyInfo(devices[ad].inputDeviceID_, 0, true, kAudioDevicePropertyStreamFormat, &propertySize, &writable); if (err != noErr) { debug_msg("error AudioDeviceGetPropertyInfo"); return 0; } err = AudioDeviceGetProperty(devices[ad].inputDeviceID_, 0, true, kAudioDevicePropertyStreamFormat, &propertySize, &(devices[ad].inputStreamBasicDescription_)); //printf("inputStreamBasicDescription_.mBytesPerFrame %d\n", devices[add].inputStreamBasicDescription_); if (err != noErr) { debug_msg("error AudioDeviceGetProperty"); return 0; } // nastavime maly endian devices[ad].inputStreamBasicDescription_.mFormatFlags &= (kAudioFormatFlagIsBigEndian & 0); if (writable) { err = AudioDeviceSetProperty(devices[ad].inputDeviceID_, NULL, 0, true, kAudioDevicePropertyStreamFormat, sizeof(AudioStreamBasicDescription), &(devices[ad].inputStreamBasicDescription_)); if (err != noErr) printf("err: AudioDeviceSetProperty: kAudioDevicePropertyStreamFormat\n"); } /* set the buffer size of the device */ /* int bufferByteSize = 8192; propertySize = sizeof(bufferByteSize); err = AudioDeviceSetProperty(devices[ad].inputDeviceID_, NULL, 0, true, kAudioDevicePropertyBufferSize, propertySize, &bufferByteSize); if (err != noErr) debug_msg("err: Set kAudioDevicePropertyBufferSize to %d\n", bufferByteSize); else debug_msg("sucessfully set kAudioDevicePropertyBufferSize to %d\n", bufferByteSize); */ // Set the device sample rate -- a temporary fix for the G5's // built-in audio and possibly other audio devices. Boolean IsInput = 0; int inChannel = 0; Float64 theAnswer = 44100; UInt32 theSize = sizeof(theAnswer); err = AudioDeviceSetProperty(devices[ad].inputDeviceID_, NULL, inChannel, IsInput, kAudioDevicePropertyNominalSampleRate, theSize, &theAnswer); if (err != noErr) { debug_msg("error AudioDeviceSetProperty\n"); return 0; } debug_msg("Sample rate, %f\n", theAnswer); #if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5) err = AudioDeviceCreateIOProcID(devices[ad].inputDeviceID_, audioIOProc, (void*)NULL, &devices[ad].inputDeviceProcID_); if (err != noErr) { debug_msg("error AudioDeviceCreateIOProcID, %s\n", GetMacOSStatusCommentString(err)); return 0; } err = OpenADefaultComponent(kAudioUnitType_Output, kAudioUnitSubType_DefaultOutput, &(devices[ad].outputUnit_)); // The HAL AU maybe a better way to in the future... //err = OpenADefaultComponent(kAudioUnitType_Output, kAudioUnitSubType_HALOutput, &(devices[ad].outputUnit_)); if (err != noErr) { debug_msg("error OpenADefaultComponent\n"); return 0; } #else // Register the AudioDeviceIOProc. err = AudioDeviceAddIOProc(devices[ad].inputDeviceID_, audioIOProc, NULL); if (err != noErr) { debug_msg("error AudioDeviceAddIOProc\n"); return 0; } err = OpenDefaultAudioOutput(&(devices[ad].outputUnit_)); if (err != noErr) { debug_msg("error OpenDefaultAudioOutput\n"); return 0; } #endif // Register a callback function to provide output data to the unit. devices[ad].input.inputProc = outputRenderer; devices[ad].input.inputProcRefCon = 0; /* These would be needed if HAL used * UInt32 enableIO =1; err = AudioUnitSetProperty(devices[ad].outputUnit_, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, (const void*)&enableIO, sizeof(UInt32)); enableIO=0; err = AudioUnitSetProperty(devices[ad].outputUnit_, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, (const void*)&enableIO, sizeof(UInt32)); if (err != noErr) { debug_msg("error AudioUnitSetProperty EnableIO with error %ld: %s\n", err, GetMacOSStatusErrorString(err)); return 0; }*/ #if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5) err = AudioUnitSetProperty(devices[ad].outputUnit_, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, 0, &(devices[ad].input), sizeof(AURenderCallbackStruct)); #else err = AudioUnitSetProperty(devices[ad].outputUnit_, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &(devices[ad].input), sizeof(AURenderCallbackStruct)); #endif if (err != noErr) { debug_msg("error AudioUnitSetProperty1 with error %ld: %s\n", err, GetMacOSStatusErrorString(err)); return 0; } // Define the Mash stream description. Mash puts 20ms of data into each read // and write call. 20ms at 8000Hz equals 160 samples. Each sample is a u_char, // so that's 160 bytes. Mash uses 8-bit mu-law internally, so we need to convert // to 16-bit linear before using the audio data. devices[ad].mashStreamBasicDescription_.mSampleRate = 8000.0; //devices[ad].mashStreamBasicDescription_.mSampleRate = ifmt->sample_rate; devices[ad].mashStreamBasicDescription_.mFormatID = kAudioFormatLinearPCM; #ifdef WORDS_BIGENDIAN devices[ad].mashStreamBasicDescription_.mFormatFlags =kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsBigEndian |kLinearPCMFormatFlagIsPacked; #else devices[ad].mashStreamBasicDescription_.mFormatFlags =kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked; #endif devices[ad].mashStreamBasicDescription_.mBytesPerPacket = 2; devices[ad].mashStreamBasicDescription_.mFramesPerPacket = 1; devices[ad].mashStreamBasicDescription_.mBytesPerFrame = 2; devices[ad].mashStreamBasicDescription_.mChannelsPerFrame = 1; devices[ad].mashStreamBasicDescription_.mBitsPerChannel = 16; // Inform the default output unit of our source format. err = AudioUnitSetProperty(devices[ad].outputUnit_, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &(devices[ad].mashStreamBasicDescription_), sizeof(AudioStreamBasicDescription)); if (err != noErr) { debug_msg("error AudioUnitSetProperty2"); printf("error setting output unit source format\n"); return 0; } // check the stream format err = AudioUnitGetPropertyInfo(devices[ad].outputUnit_, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &propertySize, &writable); if (err != noErr) debug_msg("err getting propert info for kAudioUnitProperty_StreamFormat\n"); err = AudioUnitGetProperty(devices[ad].outputUnit_, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamdesc_, &propertySize); if (err != noErr) debug_msg("err getting values for kAudioUnitProperty_StreamFormat\n"); char name[128]; audio_format_name(ifmt, name, 128); debug_msg("Requested ifmt %s\n",name); debug_msg("ifmt bytes pre block: %d\n",ifmt->bytes_per_block); // handle the requested format if (ifmt->encoding != DEV_S16) { audio_format_change_encoding(ifmt, DEV_S16); debug_msg("Requested ifmt changed to %s\n",name); debug_msg("ifmt bytes pre block: %d\n",ifmt->bytes_per_block); } audio_format_name(ofmt, name, 128); debug_msg("Requested ofmt %s\n",name); debug_msg("ofmt bytes pre block: %d\n",ofmt->bytes_per_block); // Allocate the read buffer and Z delay line. //readBufferSize_ = 8192; readBufferSize_ = ifmt->bytes_per_block * ringBufferFactor_; //readBufferSize_ = 320; //printf("readBufferSize_ %d\n", readBufferSize_); readBuffer_ = malloc(sizeof(u_char)*readBufferSize_); bzero(readBuffer_, readBufferSize_ * sizeof(u_char)); //memset(readBuffer_, PCMU_AUDIO_ZERO, readBufferSize_); //inputReadIndex_ = -1; inputReadIndex_ = 0; inputWriteIndex_ = 0; zLine_ = malloc(sizeof(double)*DECIM441_LENGTH / 80); availableInput_ = 0; // Allocate the write buffer. //writeBufferSize_ = 8000; writeBufferSize_ = ofmt->bytes_per_block * ringBufferFactor_; writeBuffer_ = malloc(sizeof(SInt16)*writeBufferSize_); bzero(writeBuffer_, writeBufferSize_ * sizeof(SInt16)); outputReadIndex_ = 0; outputWriteIndex_ = 0; //outputWriteIndex_ = -1; // Start audio processing. err = AudioUnitInitialize(devices[ad].outputUnit_); if (err != noErr) { debug_msg("error AudioUnitInitialize\n"); return 0; } err = AudioDeviceStart(devices[ad].inputDeviceID_, audioIOProc); if (err != noErr) { fprintf(stderr, "Input device error: AudioDeviceStart\n"); return 0; } err = AudioOutputUnitStart(devices[ad].outputUnit_); if (err != noErr) { fprintf(stderr, "Output device error: AudioOutputUnitStart\n"); return 0; } // Inform the default output unit of our source format. /* err = AudioUnitSetProperty(devices[ad].outputUnit_, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &(devices[ad].mashStreamBasicDescription_), sizeof(AudioStreamBasicDescription)); if (err != noErr) { debug_msg("error AudioUnitSetProperty3"); return 0; } */ return 1; };
void CoreAudioOutDriver::open(device_id_t device, int sample_rate, sample_format form, int channels, int num_samples, int num_periods) { if (this->is_open()) throw std::logic_error("Device already open"); if (form != SF_16LE) throw std::invalid_argument("Unknown sample format"); m_impl->m_logger = logger; AudioDeviceID devid = GetDeviceID(logger, device); if (devid == kAudioDeviceUnknown) throw std::invalid_argument("Unknown device id"); OSStatus err; const bool isInput = false; UInt32 propsize; AudioValueRange bufferRange; // check that the desired value is within the allowed range propsize = sizeof(bufferRange); err = AudioDeviceGetProperty(devid, 0, false, kAudioDevicePropertyBufferFrameSizeRange, &propsize, &bufferRange); if (err != kAudioHardwareNoError) { throw std::runtime_error("Could not get buffer range"); } propsize = sizeof(UInt32); UInt32 frames = my_min<int>(my_max<int>(num_samples, (int) bufferRange.mMinimum), (int) bufferRange.mMaximum); err = AudioDeviceSetProperty(devid, NULL, 0, isInput, kAudioDevicePropertyBufferFrameSize, propsize, &frames); if (err != kAudioHardwareNoError) { throw std::runtime_error("Could not set buffer size"); } propsize = sizeof(frames); err = AudioDeviceGetProperty(devid, 0, isInput, kAudioDevicePropertyBufferFrameSize, &propsize, &frames); if (err != kAudioHardwareNoError) { throw std::runtime_error("Could not read buffer size"); } char bbc[256] = {0}; sprintf(bbc, "Buffer size in frames: %i", frames); logger(2, bbc); Float64 sampleRate = sample_rate; propsize = sizeof(sampleRate); err = AudioDeviceSetProperty(devid, NULL, 0, isInput, kAudioDevicePropertyNominalSampleRate, propsize, &sampleRate); if (err != kAudioHardwareNoError) { throw std::runtime_error("Could not set sample rate"); } print_info(devid, logger, isInput); propsize = sizeof(m_impl->m_format); err = AudioDeviceGetProperty(devid, 0, isInput, kAudioDevicePropertyStreamFormat, &propsize, &m_impl->m_format); if (err != kAudioHardwareNoError) { throw std::runtime_error("Could not get audio format"); } // Desired format memset(&m_impl->m_input_format, 0, sizeof(m_impl->m_input_format)); // set channels, format to SF_16LE m_impl->m_input_format.mSampleRate = sample_rate; m_impl->m_input_format.mFormatID = kAudioFormatLinearPCM; m_impl->m_input_format.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked; m_impl->m_input_format.mBytesPerPacket = 2*channels; m_impl->m_input_format.mFramesPerPacket = 1; m_impl->m_input_format.mBytesPerFrame = m_impl->m_input_format.mBytesPerPacket; m_impl->m_input_format.mChannelsPerFrame = channels; m_impl->m_input_format.mBitsPerChannel = 16; #define USE_COMPLEX_AUDIO_CONVERTER //#define USE_SIMPLE_AUDIO_CONVERTER #if defined(USE_SIMPLE_AUDIO_CONVERTER) m_impl->m_converter = new SimpleConverter(m_impl->m_input_format, m_impl->m_format); #elif defined (USE_COMPLEX_AUDIO_CONVERTER) m_impl->m_converter = new ComplexConverter(m_impl->m_input_format, m_impl->m_format); #else // TODO: this works only for 2 channels float to 1 channel mono 16LE! m_impl->m_converter = new Mono16LEPCMToStereoFloat; #endif print_format pf1(logger, "Device Format\n"); pf1(m_impl->m_format); print_format pf2(logger, "Input Format\n"); pf2(m_impl->m_input_format); // Set the buffer latency (audio output is only started after // the buffer contains m_min_buffer samples). m_impl->m_min_buffer = num_samples*num_periods; m_impl->m_ID = devid; AudioDeviceAddIOProc(devid, Impl::OutputIOProc, m_impl.get()); }
static AUDIO_OUT * macosx_open (int channels, int samplerate) { MACOSX_AUDIO_OUT *macosx_out ; OSStatus err ; size_t count ; if ((macosx_out = malloc (sizeof (MACOSX_AUDIO_OUT))) == NULL) { perror ("macosx_open : malloc ") ; exit (1) ; } ; macosx_out->magic = MACOSX_MAGIC ; macosx_out->channels = channels ; macosx_out->samplerate = samplerate ; macosx_out->device = kAudioDeviceUnknown ; /* get the default output device for the HAL */ count = sizeof (AudioDeviceID) ; if ((err = AudioHardwareGetProperty (kAudioHardwarePropertyDefaultOutputDevice, &count, (void *) &(macosx_out->device))) != noErr) { printf ("AudioHardwareGetProperty failed.\n") ; free (macosx_out) ; return NULL ; } ; /* get the buffersize that the default device uses for IO */ count = sizeof (UInt32) ; if ((err = AudioDeviceGetProperty (macosx_out->device, 0, false, kAudioDevicePropertyBufferSize, &count, &(macosx_out->buffer_size))) != noErr) { printf ("AudioDeviceGetProperty (AudioDeviceGetProperty) failed.\n") ; free (macosx_out) ; return NULL ; } ; /* get a description of the data format used by the default device */ count = sizeof (AudioStreamBasicDescription) ; if ((err = AudioDeviceGetProperty (macosx_out->device, 0, false, kAudioDevicePropertyStreamFormat, &count, &(macosx_out->format))) != noErr) { printf ("AudioDeviceGetProperty (kAudioDevicePropertyStreamFormat) failed.\n") ; free (macosx_out) ; return NULL ; } ; macosx_out->format.mSampleRate = samplerate ; macosx_out->format.mChannelsPerFrame = channels ; if ((err = AudioDeviceSetProperty (macosx_out->device, NULL, 0, false, kAudioDevicePropertyStreamFormat, sizeof (AudioStreamBasicDescription), &(macosx_out->format))) != noErr) { printf ("AudioDeviceSetProperty (kAudioDevicePropertyStreamFormat) failed.\n") ; free (macosx_out) ; return NULL ; } ; /* we want linear pcm */ if (macosx_out->format.mFormatID != kAudioFormatLinearPCM) { free (macosx_out) ; return NULL ; } ; macosx_out->done_playing = 0 ; /* Fire off the device. */ if ((err = AudioDeviceAddIOProc (macosx_out->device, macosx_audio_out_callback, (void *) macosx_out)) != noErr) { printf ("AudioDeviceAddIOProc failed.\n") ; free (macosx_out) ; return NULL ; } ; return (MACOSX_AUDIO_OUT *) macosx_out ; } /* macosx_open */
static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaStream** s, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData ) { PaError err = paNoError; PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation *)hostApi; PaMacCoreStream *stream = PaUtil_AllocateMemory(sizeof(PaMacCoreStream)); stream->isActive = 0; stream->isStopped = 1; stream->inputDevice = kAudioDeviceUnknown; stream->outputDevice = kAudioDeviceUnknown; PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, ( (streamCallback) ? &macCoreHostApi->callbackStreamInterface : &macCoreHostApi->blockingStreamInterface ), streamCallback, userData ); PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); *s = (PaStream*)stream; PaMacClientData *clientData = PaUtil_AllocateMemory(sizeof(PaMacClientData)); clientData->stream = stream; clientData->callback = streamCallback; clientData->userData = userData; clientData->inputBuffer = 0; clientData->outputBuffer = 0; clientData->ditherGenerator = PaUtil_AllocateMemory(sizeof(PaUtilTriangularDitherGenerator)); PaUtil_InitializeTriangularDitherState(clientData->ditherGenerator); if (inputParameters != NULL) { stream->inputDevice = macCoreHostApi->macCoreDeviceIds[inputParameters->device]; clientData->inputConverter = PaUtil_SelectConverter(paFloat32, inputParameters->sampleFormat, streamFlags); clientData->inputBuffer = PaUtil_AllocateMemory(Pa_GetSampleSize(inputParameters->sampleFormat) * framesPerBuffer * inputParameters->channelCount); clientData->inputChannelCount = inputParameters->channelCount; clientData->inputSampleFormat = inputParameters->sampleFormat; err = SetUpUnidirectionalStream(stream->inputDevice, sampleRate, framesPerBuffer, 1); } if (err == paNoError && outputParameters != NULL) { stream->outputDevice = macCoreHostApi->macCoreDeviceIds[outputParameters->device]; clientData->outputConverter = PaUtil_SelectConverter(outputParameters->sampleFormat, paFloat32, streamFlags); clientData->outputBuffer = PaUtil_AllocateMemory(Pa_GetSampleSize(outputParameters->sampleFormat) * framesPerBuffer * outputParameters->channelCount); clientData->outputChannelCount = outputParameters->channelCount; clientData->outputSampleFormat = outputParameters->sampleFormat; err = SetUpUnidirectionalStream(stream->outputDevice, sampleRate, framesPerBuffer, 0); } if (inputParameters == NULL || outputParameters == NULL || stream->inputDevice == stream->outputDevice) { AudioDeviceID device = (inputParameters == NULL) ? stream->outputDevice : stream->inputDevice; AudioDeviceAddIOProc(device, AudioIOProc, clientData); } else { // using different devices for input and output AudioDeviceAddIOProc(stream->inputDevice, AudioInputProc, clientData); AudioDeviceAddIOProc(stream->outputDevice, AudioOutputProc, clientData); } return err; }
// Initialize the BlockSound class BlockSound::BlockSound() { sample_size = 0; #ifdef __APPLE__ remaining = 0; UInt32 size = sizeof(device); if (AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &size, (void *)&device) != noErr) return; size = sizeof(format); if (AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyStreamFormat, &size, &format) != noErr) return; // Set up a format we like... format.mSampleRate = 44100.0; // 44.1kHz format.mChannelsPerFrame = 2; // stereo if (AudioDeviceSetProperty(device, NULL, 0, false, kAudioDevicePropertyStreamFormat, sizeof(format), &format) != noErr) return; // Check we got linear pcm - what to do if we did not ??? if (format.mFormatID != kAudioFormatLinearPCM) return; // Attach the callback and start the device # if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 if (AudioDeviceCreateIOProcID(device, audio_cb, (void *)this, &audio_proc_id) != noErr) return; AudioDeviceStart(device, audio_proc_id); # else if (AudioDeviceAddIOProc(device, audio_cb, (void *)this) != noErr) return; AudioDeviceStart(device, audio_cb); # endif sample_size = (int)format.mSampleRate; #elif defined(WIN32) WAVEFORMATEX format; memset(&format, 0, sizeof(format)); format.cbSize = sizeof(format); format.wFormatTag = WAVE_FORMAT_PCM; format.nChannels = 2; format.nSamplesPerSec = 44100; format.nAvgBytesPerSec = 44100 * 4; format.nBlockAlign = 4; format.wBitsPerSample = 16; data_handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, format.nSamplesPerSec * 4); if (!data_handle) return; data_ptr = (LPSTR)GlobalLock(data_handle); header_handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, sizeof(WAVEHDR)); if (!header_handle) return; header_ptr = (WAVEHDR *)GlobalLock(header_handle); header_ptr->lpData = data_ptr; header_ptr->dwFlags = 0; header_ptr->dwLoops = 0; if (waveOutOpen(&device, WAVE_MAPPER, &format, 0, 0, WAVE_ALLOWSYNC) != MMSYSERR_NOERROR) return; sample_size = format.nSamplesPerSec; #else # ifdef HAVE_ALSA_ASOUNDLIB_H handle = NULL; if (snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0) >= 0) { // Initialize PCM sound stuff... snd_pcm_hw_params_t *params; snd_pcm_hw_params_alloca(¶ms); snd_pcm_hw_params_any(handle, params); snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16); snd_pcm_hw_params_set_channels(handle, params, 2); unsigned rate = 44100; int dir; snd_pcm_hw_params_set_rate_near(handle, params, &rate, &dir); snd_pcm_uframes_t period = (int)rate; snd_pcm_hw_params_set_period_size_near(handle, params, &period, &dir); sample_size = rate; if (snd_pcm_hw_params(handle, params) < 0) { sample_size = 0; snd_pcm_close(handle); handle = NULL; } } # endif // HAVE_ALSA_ASOUNDLIB_H #endif // __APPLE__ if (sample_size) { // Make an explosion sound by passing white noise through a low pass // filter with a decreasing frequency... sample_data = new short[2 * sample_size]; short *sample_ptr = sample_data; int max_sample = 2 * sample_size - 2; *sample_ptr++ = 0; *sample_ptr++ = 0; for (int j = max_sample; j > 0; j --, sample_ptr ++) { float freq = (float)j / (float)max_sample; float volume = 32767.0 * (0.5 * sqrt(freq) + 0.5); float sample = 0.0001 * ((rand() % 20001) - 10000); *sample_ptr = (int)(volume * freq * sample + (1.0 - freq) * sample_ptr[-2]); } } }
SndCoreAudio::SndCoreAudio(int channels,int bufframes, int buffnos, float norm, SndObj** inObjs, AudioDeviceID dev, int vecsize, float sr): SndIO((channels < 2 ? 2 : channels), sizeof(float)*8, inObjs, vecsize, sr) { UInt32 psize; int i; UInt32 obufframes, ibufframes; AudioStreamBasicDescription format; m_norm = norm ? norm : 1.f; if(dev=DEV_DEFAULT){ psize = sizeof(AudioDeviceID); AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &psize, &m_dev); } else m_dev = dev; m_bufframes = bufframes; m_buffsize = bufframes*sizeof(float)*m_channels; m_buffitems = bufframes*m_channels; m_buffnos = buffnos; psize = 4; // set the buffer size // output AudioDeviceSetProperty(m_dev,NULL,0,false, kAudioDevicePropertyBufferFrameSize, psize, &m_bufframes); // input AudioDeviceSetProperty(m_dev,NULL,0,true, kAudioDevicePropertyBufferFrameSize, psize, &m_bufframes); // check that it matches the expected size AudioDeviceGetProperty(m_dev,0,true, kAudioDevicePropertyBufferFrameSize, &psize, &ibufframes); AudioDeviceGetProperty(m_dev,0,false, kAudioDevicePropertyBufferFrameSize, &psize, &obufframes); if(ibufframes != m_bufframes){ if(ibufframes == obufframes) m_bufframes = obufframes; else { m_error = 21; return; } } m_format.mSampleRate = m_sr; m_format.mFormatID = kAudioFormatLinearPCM; m_format.mFormatFlags = kAudioFormatFlagIsFloat; m_format.mBytesPerPacket = sizeof(float)*m_channels; m_format.mFramesPerPacket = 1; m_format.mBytesPerFrame = format.mBytesPerPacket; m_format.mChannelsPerFrame = m_channels; m_format.mBitsPerChannel = sizeof(float); psize = sizeof(AudioStreamBasicDescription); AudioDeviceSetProperty(m_dev,NULL,0,true, kAudioDevicePropertyStreamFormat, psize, &m_format); AudioDeviceSetProperty(m_dev,NULL,0,false, kAudioDevicePropertyStreamFormat, psize, &m_format); AudioDeviceGetProperty(m_dev,0,false, kAudioDevicePropertyStreamFormat, &psize, &format); if(format.mSampleRate != m_sr){ m_error = 22; return; } if(format.mChannelsPerFrame != m_channels){ m_error = 23; return; } m_outbuffs = new float*[m_buffnos]; m_inbuffs = new float*[m_buffnos]; m_inused = new bool[m_buffnos]; m_outused = new bool[m_buffnos]; for(i=0; i < m_buffnos; i++){ if(!(m_inbuffs[i] = new float[m_bufframes*m_channels])){ m_error = 24; return; } if(!(m_outbuffs[i] = new float[m_bufframes*m_channels])){ m_error = 25; return; } m_inused[i] = m_outused[i] = true; } m_incurbuff = m_outcurbuff = m_iocurbuff = 0; m_incount = m_outcount = 0; AudioDeviceAddIOProc(m_dev, SndObj_IOProcEntry, this); AudioDeviceStart(m_dev, SndObj_IOProcEntry); }
static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque) { OSStatus status; coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; UInt32 propertySize; int err; const char *typ = "playback"; AudioValueRange frameRange; CoreaudioConf *conf = drv_opaque; /* create mutex */ err = pthread_mutex_init(&core->mutex, NULL); if (err) { dolog("Could not create mutex\nReason: %s\n", strerror (err)); return -1; } audio_pcm_init_info (&hw->info, as); /* open default output device */ propertySize = sizeof(core->outputDeviceID); status = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice, &propertySize, &core->outputDeviceID); if (status != kAudioHardwareNoError) { coreaudio_logerr2 (status, typ, "Could not get default output Device\n"); return -1; } if (core->outputDeviceID == kAudioDeviceUnknown) { dolog ("Could not initialize %s - Unknown Audiodevice\n", typ); return -1; } /* get minimum and maximum buffer frame sizes */ propertySize = sizeof(frameRange); status = AudioDeviceGetProperty( core->outputDeviceID, 0, 0, kAudioDevicePropertyBufferFrameSizeRange, &propertySize, &frameRange); if (status != kAudioHardwareNoError) { coreaudio_logerr2 (status, typ, "Could not get device buffer frame range\n"); return -1; } if (frameRange.mMinimum > conf->buffer_frames) { core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum; dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum); } else if (frameRange.mMaximum < conf->buffer_frames) { core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum; dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum); } else { core->audioDevicePropertyBufferFrameSize = conf->buffer_frames; } /* set Buffer Frame Size */ propertySize = sizeof(core->audioDevicePropertyBufferFrameSize); status = AudioDeviceSetProperty( core->outputDeviceID, NULL, 0, false, kAudioDevicePropertyBufferFrameSize, propertySize, &core->audioDevicePropertyBufferFrameSize); if (status != kAudioHardwareNoError) { coreaudio_logerr2 (status, typ, "Could not set device buffer frame size %" PRIu32 "\n", (uint32_t)core->audioDevicePropertyBufferFrameSize); return -1; } /* get Buffer Frame Size */ propertySize = sizeof(core->audioDevicePropertyBufferFrameSize); status = AudioDeviceGetProperty( core->outputDeviceID, 0, false, kAudioDevicePropertyBufferFrameSize, &propertySize, &core->audioDevicePropertyBufferFrameSize); if (status != kAudioHardwareNoError) { coreaudio_logerr2 (status, typ, "Could not get device buffer frame size\n"); return -1; } hw->samples = conf->nbuffers * core->audioDevicePropertyBufferFrameSize; /* get StreamFormat */ propertySize = sizeof(core->outputStreamBasicDescription); status = AudioDeviceGetProperty( core->outputDeviceID, 0, false, kAudioDevicePropertyStreamFormat, &propertySize, &core->outputStreamBasicDescription); if (status != kAudioHardwareNoError) { coreaudio_logerr2 (status, typ, "Could not get Device Stream properties\n"); core->outputDeviceID = kAudioDeviceUnknown; return -1; } /* set Samplerate */ core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq; propertySize = sizeof(core->outputStreamBasicDescription); status = AudioDeviceSetProperty( core->outputDeviceID, 0, 0, 0, kAudioDevicePropertyStreamFormat, propertySize, &core->outputStreamBasicDescription); if (status != kAudioHardwareNoError) { coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n", as->freq); core->outputDeviceID = kAudioDeviceUnknown; return -1; } /* set Callback */ status = AudioDeviceAddIOProc(core->outputDeviceID, audioDeviceIOProc, hw); if (status != kAudioHardwareNoError) { coreaudio_logerr2 (status, typ, "Could not set IOProc\n"); core->outputDeviceID = kAudioDeviceUnknown; return -1; } /* start Playback */ if (!isPlaying(core->outputDeviceID)) { status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc); if (status != kAudioHardwareNoError) { coreaudio_logerr2 (status, typ, "Could not start playback\n"); AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc); core->outputDeviceID = kAudioDeviceUnknown; return -1; } } return 0; }
static int coreaudio_voice_init (coreaudioVoice* core, struct audsettings* as, int frameSize, AudioDeviceIOProc ioproc, void* hw, int input) { OSStatus status; UInt32 propertySize; int err; int bits = 8; AudioValueRange frameRange; const char* typ = input ? "input" : "playback"; core->isInput = input ? true : false; /* create mutex */ err = pthread_mutex_init(&core->mutex, NULL); if (err) { dolog("Could not create mutex\nReason: %s\n", strerror (err)); return -1; } if (as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) { bits = 16; } // TODO: audio_pcm_init_info (&hw->info, as); /* open default output device */ /* note: we use DefaultSystemOutputDevice because DefaultOutputDevice seems to * always link to the internal speakers, and not the ones selected through system properties * go figure... */ propertySize = sizeof(core->deviceID); status = AudioHardwareGetProperty( input ? kAudioHardwarePropertyDefaultInputDevice : kAudioHardwarePropertyDefaultSystemOutputDevice, &propertySize, &core->deviceID); if (status != kAudioHardwareNoError) { coreaudio_logerr2 (status, typ, "Could not get default %s device\n", typ); return -1; } if (core->deviceID == kAudioDeviceUnknown) { dolog ("Could not initialize %s - Unknown Audiodevice\n", typ); return -1; } /* get minimum and maximum buffer frame sizes */ propertySize = sizeof(frameRange); status = AudioDeviceGetProperty( core->deviceID, 0, core->isInput, kAudioDevicePropertyBufferFrameSizeRange, &propertySize, &frameRange); if (status != kAudioHardwareNoError) { coreaudio_logerr2 (status, typ, "Could not get device buffer frame range\n"); return -1; } if (frameRange.mMinimum > frameSize) { core->bufferFrameSize = (UInt32) frameRange.mMinimum; dolog ("warning: Upsizing Output Buffer Frames to %f\n", frameRange.mMinimum); } else if (frameRange.mMaximum < frameSize) { core->bufferFrameSize = (UInt32) frameRange.mMaximum; dolog ("warning: Downsizing Output Buffer Frames to %f\n", frameRange.mMaximum); } else { core->bufferFrameSize = frameSize; } /* set Buffer Frame Size */ propertySize = sizeof(core->bufferFrameSize); status = AudioDeviceSetProperty( core->deviceID, NULL, 0, core->isInput, kAudioDevicePropertyBufferFrameSize, propertySize, &core->bufferFrameSize); if (status != kAudioHardwareNoError) { coreaudio_logerr2 (status, typ, "Could not set device buffer frame size %ld\n", core->bufferFrameSize); return -1; } /* get Buffer Frame Size */ propertySize = sizeof(core->bufferFrameSize); status = AudioDeviceGetProperty( core->deviceID, 0, core->isInput, kAudioDevicePropertyBufferFrameSize, &propertySize, &core->bufferFrameSize); if (status != kAudioHardwareNoError) { coreaudio_logerr2 (status, typ, "Could not get device buffer frame size\n"); return -1; } // TODO: hw->samples = *pNBuffers * core->bufferFrameSize; /* get StreamFormat */ propertySize = sizeof(core->streamBasicDescription); status = AudioDeviceGetProperty( core->deviceID, 0, core->isInput, kAudioDevicePropertyStreamFormat, &propertySize, &core->streamBasicDescription); if (status != kAudioHardwareNoError) { coreaudio_logerr2 (status, typ, "Could not get Device Stream properties\n"); core->deviceID = kAudioDeviceUnknown; return -1; } /* set Samplerate */ core->streamBasicDescription.mSampleRate = (Float64) as->freq; propertySize = sizeof(core->streamBasicDescription); status = AudioDeviceSetProperty( core->deviceID, 0, 0, core->isInput, kAudioDevicePropertyStreamFormat, propertySize, &core->streamBasicDescription); if (status != kAudioHardwareNoError) { coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n", as->freq); core->deviceID = kAudioDeviceUnknown; return -1; } /* set Callback */ core->ioproc = ioproc; status = AudioDeviceAddIOProc(core->deviceID, ioproc, hw); if (status != kAudioHardwareNoError) { coreaudio_logerr2 (status, typ, "Could not set IOProc\n"); core->deviceID = kAudioDeviceUnknown; return -1; } /* start Playback */ if (!input && !coreaudio_voice_isPlaying(core)) { status = AudioDeviceStart(core->deviceID, core->ioproc); if (status != kAudioHardwareNoError) { coreaudio_logerr2 (status, typ, "Could not start playback\n"); AudioDeviceRemoveIOProc(core->deviceID, core->ioproc); core->deviceID = kAudioDeviceUnknown; return -1; } } return 0; }
static void macosx_play (int argc, char *argv []) { MacOSXAudioData audio_data ; OSStatus err ; UInt32 count, buffer_size ; int k ; audio_data.fake_stereo = 0 ; audio_data.device = kAudioDeviceUnknown ; /* get the default output device for the HAL */ count = sizeof (AudioDeviceID) ; if ((err = AudioHardwareGetProperty (kAudioHardwarePropertyDefaultOutputDevice, &count, (void *) &(audio_data.device))) != noErr) { printf ("AudioHardwareGetProperty (kAudioDevicePropertyDefaultOutputDevice) failed.\n") ; return ; } ; /* get the buffersize that the default device uses for IO */ count = sizeof (UInt32) ; if ((err = AudioDeviceGetProperty (audio_data.device, 0, false, kAudioDevicePropertyBufferSize, &count, &buffer_size)) != noErr) { printf ("AudioDeviceGetProperty (kAudioDevicePropertyBufferSize) failed.\n") ; return ; } ; /* get a description of the data format used by the default device */ count = sizeof (AudioStreamBasicDescription) ; if ((err = AudioDeviceGetProperty (audio_data.device, 0, false, kAudioDevicePropertyStreamFormat, &count, &(audio_data.format))) != noErr) { printf ("AudioDeviceGetProperty (kAudioDevicePropertyStreamFormat) failed.\n") ; return ; } ; /* Base setup completed. Now play files. */ for (k = 1 ; k < argc ; k++) { printf ("Playing %s\n", argv [k]) ; if (! (audio_data.sndfile = sf_open (argv [k], SFM_READ, &(audio_data.sfinfo)))) { puts (sf_strerror (NULL)) ; continue ; } ; if (audio_data.sfinfo.channels < 1 || audio_data.sfinfo.channels > 2) { printf ("Error : channels = %d.\n", audio_data.sfinfo.channels) ; continue ; } ; audio_data.format.mSampleRate = audio_data.sfinfo.samplerate ; if (audio_data.sfinfo.channels == 1) { audio_data.format.mChannelsPerFrame = 2 ; audio_data.fake_stereo = 1 ; } else audio_data.format.mChannelsPerFrame = audio_data.sfinfo.channels ; if ((err = AudioDeviceSetProperty (audio_data.device, NULL, 0, false, kAudioDevicePropertyStreamFormat, sizeof (AudioStreamBasicDescription), &(audio_data.format))) != noErr) { printf ("AudioDeviceSetProperty (kAudioDevicePropertyStreamFormat) failed.\n") ; return ; } ; /* we want linear pcm */ if (audio_data.format.mFormatID != kAudioFormatLinearPCM) return ; /* Fire off the device. */ if ((err = AudioDeviceAddIOProc (audio_data.device, macosx_audio_out_callback, (void *) &audio_data)) != noErr) { printf ("AudioDeviceAddIOProc failed.\n") ; return ; } ; err = AudioDeviceStart (audio_data.device, macosx_audio_out_callback) ; if (err != noErr) return ; audio_data.done_playing = SF_FALSE ; while (audio_data.done_playing == SF_FALSE) usleep (10 * 1000) ; /* 10 000 milliseconds. */ if ((err = AudioDeviceStop (audio_data.device, macosx_audio_out_callback)) != noErr) { printf ("AudioDeviceStop failed.\n") ; return ; } ; err = AudioDeviceRemoveIOProc (audio_data.device, macosx_audio_out_callback) ; if (err != noErr) { printf ("AudioDeviceRemoveIOProc failed.\n") ; return ; } ; sf_close (audio_data.sndfile) ; } ; return ; } /* macosx_play */
static int audio_init(error_t *error) { UInt32 size; int ret; AudioStreamBasicDescription format; UInt32 byte_count; /* get device */ size = sizeof(audio.device); ret = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &size, &audio.device); if (ret != 0) { error_set(error, "Could not get default audio device"); return 0; } if (audio.device == kAudioDeviceUnknown) { error_set(error, "Unknown audio device"); return 0; } /* check that the format is pcm */ size = sizeof(format); ret = AudioDeviceGetProperty(audio.device, 0, false, kAudioDevicePropertyStreamFormat, &size, &format); if (ret != 0) { error_set(error, "Could not get the stream format"); return 0; } if (format.mFormatID != kAudioFormatLinearPCM) { error_set(error, "The output device is not using PCM format"); return 0; } /* set the buffer size, channels, samplerate */ /* XXX channels, samplerate */ size = sizeof(byte_count); ret = AudioDeviceGetProperty(audio.device, 0, false, kAudioDevicePropertyBufferSize, &size, &byte_count); if (ret) { error_set(error, "Could not get the buffer size"); return 0; } byte_count = 1152 * 2 * sizeof(float); ret = AudioDeviceSetProperty(audio.device, NULL, 0, false, kAudioDevicePropertyBufferSize, size, &byte_count); if (ret) { error_set(error, "Could not set the buffer size"); return 0; } /* initialize the ring buffer */ rb_init(&audio.rb); ret = AudioDeviceAddIOProc(audio.device, audio_play_proc, NULL); if (ret) { error_set(error, "Could not start the IO proc"); return 0; } audio_initialized = 1; return 1; }
/* ========== idAudioHardwareOSX::Initialize ========== */ bool idAudioHardwareOSX::Initialize( ) { UInt32 size; OSStatus status; int i, deviceCount; AudioDeviceID *deviceList; char buf[ 1024 ]; status = AudioHardwareGetPropertyInfo( kAudioHardwarePropertyDevices, &size, NULL ); if ( status != kAudioHardwareNoError ) { common->Warning( "AudioHardwareGetPropertyInfo kAudioHardwarePropertyDevices failed. status: %s", ExtractStatus( status ) ); InitFailed(); return false; } deviceCount = size / sizeof( AudioDeviceID ); if ( !deviceCount ) { common->Printf( "No sound device found\n" ); InitFailed(); return false; } deviceList = (AudioDeviceID*)malloc( size ); status = AudioHardwareGetProperty( kAudioHardwarePropertyDevices, &size, deviceList ); if ( status != kAudioHardwareNoError ) { common->Warning( "AudioHardwareGetProperty kAudioHardwarePropertyDevices failed. status: %s", ExtractStatus( status ) ); free( deviceList ); InitFailed(); return false; } common->Printf( "%d sound device(s)\n", deviceCount ); for( i = 0; i < deviceCount; i++ ) { size = 1024; status = AudioDeviceGetProperty( deviceList[ i ], 0, false, kAudioDevicePropertyDeviceName, &size, buf ); if ( status != kAudioHardwareNoError ) { common->Warning( "AudioDeviceGetProperty kAudioDevicePropertyDeviceName %d failed. status: %s", i, ExtractStatus( status ) ); free( deviceList ); InitFailed(); return false; } common->Printf( " %d: ID %d, %s - ", i, deviceList[ i ], buf ); size = 1024; status = AudioDeviceGetProperty( deviceList[ i ], 0, false, kAudioDevicePropertyDeviceManufacturer, &size, buf ); if ( status != kAudioHardwareNoError ) { common->Warning( "AudioDeviceGetProperty kAudioDevicePropertyDeviceManufacturer %d failed. status: %s", i, ExtractStatus( status ) ); free( deviceList ); InitFailed(); return false; } common->Printf( "%s\n", buf ); } if ( s_device.GetInteger() != -1 && s_device.GetInteger() < deviceCount ) { selectedDevice = deviceList[ s_device.GetInteger() ]; common->Printf( "s_device: device ID %d\n", selectedDevice ); } else { size = sizeof( selectedDevice ); status = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice, &size, &selectedDevice ); if ( status != kAudioHardwareNoError ) { common->Warning( "AudioHardwareGetProperty kAudioHardwarePropertyDefaultOutputDevice failed. status: %s", ExtractStatus( status ) ); free( deviceList ); InitFailed(); return false; } common->Printf( "select default device, ID %d\n", selectedDevice ); } free( deviceList ); deviceList = NULL; /* // setup a listener to watch for changes to properties status = AudioDeviceAddPropertyListener( selectedDevice, 0, false, kAudioDeviceProcessorOverload, DeviceListener, this ); if ( status != kAudioHardwareNoError ) { common->Warning( "AudioDeviceAddPropertyListener kAudioDeviceProcessorOverload failed. status: %s", ExtractStatus( status ) ); InitFailed(); return; } */ Float64 sampleRate; size = sizeof( sampleRate ); status = AudioDeviceGetProperty( selectedDevice, 0, false, kAudioDevicePropertyNominalSampleRate, &size, &sampleRate ); if ( status != kAudioHardwareNoError ) { common->Warning( "AudioDeviceGetProperty %d kAudioDevicePropertyNominalSampleRate failed. status: %s", selectedDevice, ExtractStatus( status ) ); InitFailed(); return false; } common->Printf( "current nominal rate: %g\n", sampleRate ); if ( sampleRate != PRIMARYFREQ ) { GetAvailableNominalSampleRates(); sampleRate = PRIMARYFREQ; common->Printf( "setting rate to: %g\n", sampleRate ); status = AudioDeviceSetProperty( selectedDevice, NULL, 0, false, kAudioDevicePropertyNominalSampleRate, size, &sampleRate ); if ( status != kAudioHardwareNoError ) { common->Warning( "AudioDeviceSetProperty %d kAudioDevicePropertyNominalSampleRate %g failed. status: %s", selectedDevice, sampleRate, ExtractStatus( status ) ); InitFailed(); return false; } } UInt32 frameSize; size = sizeof( UInt32 ); status = AudioDeviceGetProperty( selectedDevice, 0, false, kAudioDevicePropertyBufferFrameSize, &size, &frameSize ); if ( status != kAudioHardwareNoError ) { common->Warning( "AudioDeviceGetProperty %d kAudioDevicePropertyBufferFrameSize failed.status: %s", selectedDevice, ExtractStatus( status ) ); InitFailed(); return false; } common->Printf( "current frame size: %d\n", frameSize ); // get the allowed frame size range AudioValueRange frameSizeRange; size = sizeof( AudioValueRange ); status = AudioDeviceGetProperty( selectedDevice, 0, false, kAudioDevicePropertyBufferFrameSizeRange, &size, &frameSizeRange ); if ( status != kAudioHardwareNoError ) { common->Warning( "AudioDeviceGetProperty %d kAudioDevicePropertyBufferFrameSizeRange failed. status: %s", selectedDevice, ExtractStatus( status ) ); InitFailed(); return false; } common->Printf( "frame size allowed range: %g %g\n", frameSizeRange.mMinimum, frameSizeRange.mMaximum ); if ( frameSizeRange.mMaximum < MIXBUFFER_SAMPLES ) { common->Warning( "can't obtain the required frame size of %d bits", MIXBUFFER_SAMPLES ); InitFailed(); return false; } if ( frameSize != (unsigned int)MIXBUFFER_SAMPLES ) { frameSize = MIXBUFFER_SAMPLES; common->Printf( "setting frame size to: %d\n", frameSize ); size = sizeof( frameSize ); status = AudioDeviceSetProperty( selectedDevice, NULL, 0, false, kAudioDevicePropertyBufferFrameSize, size, &frameSize ); if ( status != kAudioHardwareNoError ) { common->Warning( "AudioDeviceSetProperty %d kAudioDevicePropertyBufferFrameSize failed. status: %s", selectedDevice, ExtractStatus( status ) ); InitFailed(); return false; } } if ( idSoundSystemLocal::s_numberOfSpeakers.GetInteger() != 2 ) { common->Warning( "only stereo sound currently supported" ); idSoundSystemLocal::s_numberOfSpeakers.SetInteger( 2 ); } UInt32 channels[ 2 ]; size = 2 * sizeof( UInt32 ); status = AudioDeviceGetProperty( selectedDevice, 0, false, kAudioDevicePropertyPreferredChannelsForStereo, &size, &channels ); if ( status != kAudioHardwareNoError ) { common->Warning( "AudioDeviceGetProperty %d kAudioDevicePropertyPreferredChannelsForStereo failed. status: %s", selectedDevice, ExtractStatus( status ) ); InitFailed(); return false; } common->Printf( "using stereo channel IDs %d %d\n", channels[ 0 ], channels[ 1 ] ); status = AudioDeviceAddIOProc( selectedDevice, DeviceIOProc, NULL ); if ( status != kAudioHardwareNoError ) { common->Warning( "AudioDeviceAddIOProc failed. status: %s", ExtractStatus( status ) ); InitFailed(); return false; } activeIOProc = true; status = AudioDeviceStart( selectedDevice, DeviceIOProc ); if ( status != kAudioHardwareNoError ) { common->Warning( "AudioDeviceStart failed. status: %s", ExtractStatus( status ) ); InitFailed(); return false; } /* // allocate the mix buffer // it has the space for ROOM_SLICES_IN_BUFFER DeviceIOProc loops mixBufferSize = dwSpeakers * dwSampleSize * dwPrimaryBitRate * ROOM_SLICES_IN_BUFFER / 8; mixBuffer = malloc( mixBufferSize ); memset( mixBuffer, 0, mixBufferSize ); */ return true; }