IOReturn AREngine::performFormatChange(IOAudioStream* inStream, const IOAudioStreamFormat* inNewFormat, const IOAudioSampleRate* inNewSampleRate) { // set up the time stamp generator if(inNewSampleRate != NULL) { mTimeStampGenerator.SetSampleRate(inNewSampleRate->whole); } // When the format of a stream changes, we have to synch the corresponding stream in the other direction // so that the reflection works without munging channels. if(inNewFormat != NULL) { // we're going to change a lot of stuff, including controls beginConfigurationChange(); // get the starting channel for the stream UInt32 theStartingChannel = inStream->getStartingChannelID(); // get the direction for the stream IOAudioStreamDirection theDirection = inStream->getDirection(); // flip the direction theDirection = (theDirection == kIOAudioStreamDirectionOutput) ? kIOAudioStreamDirectionInput : kIOAudioStreamDirectionOutput; // look up the stream in the opposite direction IOAudioStream* theOppositeStream = getAudioStream(theDirection, theStartingChannel); // tell the opposite stream to change format too if(theOppositeStream != NULL) { theOppositeStream->setFormat(inNewFormat, false); } // we're done changing stuff completeConfigurationChange(); } return kIOReturnSuccess; }
IOAudioStream *kXAudioEngine::createNewAudioStream(int chn,IOAudioStreamDirection direction, UInt32 sampleBufferSize) { IOAudioStream *audioStream = new IOAudioStream; if (audioStream) { if (!audioStream->initWithAudioEngine(this, direction, 1)) { audioStream->release(); } else { IOAudioSampleRate rate; void *sampleBuffer=NULL; IOAudioStreamFormat format = { 1, // num channels kIOAudioStreamSampleFormatLinearPCM, // sample format kIOAudioStreamNumericRepresentationSignedInt, // numeric format bps, // bit depth bps, // bit width kIOAudioStreamAlignmentHighByte, // high byte aligned - unused because bit depth == bit width kIOAudioStreamByteOrderLittleEndian, // little endian true, // format is mixable 0 // driver-defined tag - unused by this driver }; kx_voice_buffer buffer; bzero(&buffer, sizeof(buffer)); buffer.desc = my_alloc_contiguous(sampleBufferSize, &(buffer.addr), &(buffer.physical)); if (!buffer.desc) return NULL; buffer.size=sampleBufferSize; buffer.that=this; buffer.notify=-n_frames; sampleBuffer=buffer.addr; // allocate memory: if(direction==kIOAudioStreamDirectionOutput) { int need_notifier=VOICE_OPEN_NOTIMER; if(chn==0) // first voice? need_notifier|=VOICE_OPEN_NOTIFY; // half/full buffer int mapping[]= { //2,3,4,5,6,7,8,9 - kX: front, rear, center+lfe, back //1,2,3,4,5,6,7,8 - OSX: front, center+lfe, rear, back 2,3,6,7,4,5,8,9 }; // wave 2/3 - front // wave 6/7 - center+lfe // wave 4/5 - rear // 8/9 - rear center/etc. int i=kx_allocate_multichannel(hw,bps,sampling_rate,need_notifier,&buffer,DEF_ASIO_ROUTING+mapping[chn]); // start with 2/3 if(i>=0) { hw->voicetable[i].asio_id=this; hw->voicetable[i].asio_mdl=0; hw->voicetable[i].asio_user_addr=0; hw->voicetable[i].asio_kernel_addr=0; hw->voicetable[i].asio_channel=chn; if(chn==0) // first? { hw->asio_notification_krnl.n_voice=i; hw->asio_notification_krnl.semi_buff=(hw->voicetable[i].param.endloop-hw->voicetable[i].param.startloop)/2; } } } else if(direction==kIOAudioStreamDirectionInput) { format.fNumChannels = 8; hw->mtr_buffer.desc = buffer.desc; hw->mtr_buffer.addr = buffer.addr; hw->mtr_buffer.size = buffer.size; hw->mtr_buffer.dma_handle = buffer.physical; //kx_writeptr(hw,FXIDX,0,0); //debug("createNewAudioStream FXBA:\n"); //kx_writeptr_prof(hw, FXBA, 0, hw->mtr_buffer.dma_handle); kx_writeptr(hw, FXBA, 0, hw->mtr_buffer.dma_handle); dword ch = (1 << (format.fNumChannels * 2)) - 1; // 24bit needs 2 physical channels debug("createNewAudioStream FXWCH/FXWC_K1: %x\n", ch); if(hw->is_10k2) { kx_writeptr(hw,FXWCL, 0, 0); kx_writeptr(hw,FXWCH, 0, ch); } else kx_writeptr(hw,FXWC_K1, 0, ch << 16); } // As part of creating a new IOAudioStream, its sample buffer needs to be set // It will automatically create a mix buffer should it be needed if(sampleBuffer && sampleBufferSize) audioStream->setSampleBuffer(sampleBuffer, sampleBufferSize); // This device only allows a single format and a choice of 2 different sample rates rate.fraction = 0; rate.whole = sampling_rate; audioStream->addAvailableFormat(&format, &rate, &rate); // Finally, the IOAudioStream's current format needs to be indicated audioStream->setFormat(&format); } } return audioStream; }
bool AREngine::CreateStreams(IOAudioSampleRate* outInitialSampleRate, UInt32* outNumberChannels) { // set the return values bool theAnswer = true; *outNumberChannels = 0; // set up some local variables OSArray* theFormatArray = NULL; OSArray* theSampleRateArray = NULL; OSString* theOSString = NULL; UInt32 theNumberStreams = NUM_STREAMS; OSNumber* theOSNumber = NULL; // get the array of formats theFormatArray = OSDynamicCast(OSArray, getProperty(FORMATS_KEY)); FailIfNULLWithAction(theFormatArray, theAnswer = false, Done, "AREngine::CreateStreams: Couldn't get the format array"); // get the array of sample rates theSampleRateArray = OSDynamicCast(OSArray, getProperty(SAMPLE_RATES_KEY)); FailIfNULLWithAction(theSampleRateArray, theAnswer = false, Done, "AREngine::CreateStreams: Couldn't get the sample rate array"); // get the description theOSString = OSDynamicCast(OSString, getProperty(DESCRIPTION_KEY)); if(theOSString != NULL) { setDescription(theOSString->getCStringNoCopy()); } // get the number of streams theOSNumber = OSDynamicCast(OSNumber, getProperty(NUM_STREAMS_KEY)); if(theOSNumber != NULL) { theNumberStreams = theOSNumber->unsigned32BitValue(); } // make the streams for(UInt32 theStreamNumber = 0; theStreamNumber < theNumberStreams; ++theStreamNumber) { // initialize some local variables bool theResult = false; UInt32 theMaxBitWidth = 0; UInt32 theMaxNumberChannels = 0; IOAudioStream* theInputStream = NULL; IOAudioStream* theOutputStream = NULL; OSCollectionIterator* theFormatIterator = NULL; OSCollectionIterator* theSampleRateIterator = NULL; OSDictionary* theFormatDictionary = NULL; IOAudioSampleRate theSampleRate = { 0, 0 }; IOAudioStreamFormat theInitialFormat; bool theInitialFormatSet = false; char theInputStreamName[32]; char theOutputStreamName[32]; UInt32 theStreamBufferSize = 0; // allocate and initialize the input stream if(theNumberStreams > 1) { snprintf(theInputStreamName, 32, "Input Stream #%ld", theStreamNumber + 1); } else { snprintf(theInputStreamName, 32, "Input Stream"); } theInputStream = new IOAudioStream; FailIfNULLWithAction(theInputStream, theAnswer = false, Error, "AREngine::CreateStreams: couldn't create the input stream"); theResult = theInputStream->initWithAudioEngine(this, kIOAudioStreamDirectionInput, *outNumberChannels + 1, theInputStreamName); FailIfWithAction(!theResult, theAnswer = false, Error, "AREngine::CreateStreams: couldn't initialize the input stream"); // allocate and initialize the output stream if(theNumberStreams > 1) { snprintf(theOutputStreamName, 32, "Output Stream #%ld", theStreamNumber + 1); } else { snprintf(theOutputStreamName, 32, "Output Stream"); } theOutputStream = new IOAudioStream; FailIfNULLWithAction(theOutputStream, theAnswer = false, Error, "AREngine::CreateStreams: couldn't create the output stream"); theResult = theOutputStream->initWithAudioEngine(this, kIOAudioStreamDirectionOutput, *outNumberChannels + 1, theOutputStreamName); FailIfWithAction(!theResult, theAnswer = false, Error, "AREngine::CreateStreams: couldn't initialize the output stream"); // make an iterator for the format array theFormatIterator = OSCollectionIterator::withCollection(theFormatArray); FailIfNULLWithAction(theFormatIterator, theAnswer = false, Error, "AREngine::CreateStreams: couldn't create the format iterator"); // make an iterator for the sample rate array theSampleRateIterator = OSCollectionIterator::withCollection(theSampleRateArray); FailIfNULLWithAction(theSampleRateIterator, theAnswer = false, Error, "AREngine::CreateStreams: couldn't create the sample rate iterator"); // iterate through the formats theFormatIterator->reset(); theFormatDictionary = (OSDictionary*)theFormatIterator->getNextObject(); while(theFormatDictionary != NULL) { // make sure we have a dictionary if(OSDynamicCast(OSDictionary, theFormatDictionary) != NULL) { // convert the dictionary into something we can deal with IOAudioStreamFormat theFormat; FailIfNULLWithAction(IOAudioStream::createFormatFromDictionary(theFormatDictionary, &theFormat), theAnswer = false, Error, "AREngine::CreateStreams: couldn't make a format out of the dictionary"); // make sure the initial format is set if(!theInitialFormatSet) { theInitialFormat = theFormat; } // iterate through the sample rates theSampleRateIterator->reset(); theOSNumber = (OSNumber*)theSampleRateIterator->getNextObject(); while(theOSNumber != NULL) { // make sure we have a number if(OSDynamicCast(OSNumber, theOSNumber) != NULL) { // get the sample rate theSampleRate.whole = theOSNumber->unsigned32BitValue(); // make sure the initial sample rate is set if(outInitialSampleRate->whole == 0) { outInitialSampleRate->whole = theSampleRate.whole; } // add the format to the input stream theInputStream->addAvailableFormat(&theFormat, &theSampleRate, &theSampleRate); // add the format to the output stream theOutputStream->addAvailableFormat(&theFormat, &theSampleRate, &theSampleRate); // track a few things theMaxNumberChannels = (theFormat.fNumChannels > theMaxNumberChannels) ? theFormat.fNumChannels : theMaxNumberChannels; theMaxBitWidth = (theFormat.fBitWidth > theMaxBitWidth) ? theFormat.fBitWidth : theMaxBitWidth; } // go to the next sample rate theOSNumber = (OSNumber*)theSampleRateIterator->getNextObject(); } } // go to the next format theFormatDictionary = (OSDictionary*)theFormatIterator->getNextObject(); } // calculate the size of the stream buffer theStreamBufferSize = mBlockSize * mNumberBlocks * theMaxNumberChannels * theMaxBitWidth / 8; // allocate the buffers if necessary if(mOutputBuffer == NULL) { // calculate the size mOutputBufferSize = theStreamBufferSize * theNumberStreams; // allocate the output buffer mOutputBuffer = (void*)IOMallocAligned(mOutputBufferSize, PAGE_SIZE); FailIfNULLWithAction(mOutputBuffer, theAnswer = false, Error, "AREngine::CreateStreams: couldn't allocate the output buffer"); // the input size is the same as the output size mInputBufferSize = mOutputBufferSize; // allocate the input buffer mInputBuffer = mOutputBuffer; } // set some info about the stream theInputStream->setTerminalType(INPUT_UNDEFINED); theOutputStream->setTerminalType(OUTPUT_UNDEFINED); // set the initial stream formats theInputStream->setFormat(&theInitialFormat, false); theOutputStream->setFormat(&theInitialFormat, false); // set the data buffer for the streams theInputStream->setSampleBuffer(&((UInt8*)mInputBuffer)[theStreamBufferSize * theStreamNumber], theStreamBufferSize); theOutputStream->setSampleBuffer(&((UInt8*)mOutputBuffer)[theStreamBufferSize * theStreamNumber], theStreamBufferSize); // add the streams to the engine addAudioStream(theInputStream); theInputStream->release(); theInputStream = NULL; addAudioStream(theOutputStream); theOutputStream->release(); theOutputStream = NULL; theFormatIterator->release(); theFormatIterator = NULL; theSampleRateIterator->release(); theSampleRateIterator = NULL; *outNumberChannels += theMaxNumberChannels; continue; Error: if(theInputStream) { theInputStream->release(); } if(theOutputStream) { theOutputStream->release(); } if(theFormatIterator) { theFormatIterator->release(); } if(theSampleRateIterator) { theSampleRateIterator->release(); } goto Done; } Done: return theAnswer; }
bool PhantomAudioEngine::createAudioStreams(IOAudioSampleRate *initialSampleRate) { bool result = false; OSNumber *number; UInt32 numStreams, streamNum; OSArray *formatArray, *sampleRateArray; UInt32 startingChannelID = 1; IOAudioControl *control; OSString *desc; OSBoolean *boolean; bool separateStreamBuffers = FALSE, separateInputBuffers = FALSE; desc = OSDynamicCast(OSString, getProperty(DESCRIPTION_KEY)); if (desc) { setDescription(desc->getCStringNoCopy()); } number = OSDynamicCast(OSNumber, getProperty(NUM_STREAMS_KEY)); if (number) { numStreams = number->unsigned32BitValue(); } else { numStreams = NUM_STREAMS; } formatArray = OSDynamicCast(OSArray, getProperty(FORMATS_KEY)); if (formatArray == NULL) { goto Done; } sampleRateArray = OSDynamicCast(OSArray, getProperty(SAMPLE_RATES_KEY)); if (sampleRateArray == NULL) { goto Done; } boolean = OSDynamicCast(OSBoolean, getProperty(SEPARATE_STREAM_BUFFERS_KEY)); if (boolean != NULL) { separateStreamBuffers = boolean->getValue(); } boolean = OSDynamicCast(OSBoolean, getProperty(SEPARATE_INPUT_BUFFERS_KEY)); if (boolean != NULL) { separateInputBuffers = boolean->getValue(); } if (separateStreamBuffers) { IOLog("PhantomAudioEngine::createAudioStreams() - Creating a separate buffer for each stream.\n"); } else { IOLog("PhantomAudioEngine::createAudioStreams() - Sharing one buffer among all streams.\n"); } if (separateInputBuffers) { IOLog("PhantomAudioEngine::createAudioStreams() - Creating separate buffers for input and output.\n"); } else { IOLog("PhantomAudioEngine::createAudioStreams() - Sharing input and output buffers.\n"); } for (streamNum = 0; streamNum < numStreams; streamNum++) { IOAudioStream *inputStream = NULL, *outputStream = NULL; UInt32 maxBitWidth = 0; UInt32 maxNumChannels = 0; OSCollectionIterator *formatIterator = NULL, *sampleRateIterator = NULL; OSDictionary *formatDict; IOAudioSampleRate sampleRate; IOAudioStreamFormat initialFormat; bool initialFormatSet; UInt32 channelID; char outputStreamName[20], inputStreamName[20]; UInt32 streamBufferSize; initialFormatSet = false; sampleRate.whole = 0; sampleRate.fraction = 0; inputStream = new IOAudioStream; if (inputStream == NULL) { goto Error; } outputStream = new IOAudioStream; if (outputStream == NULL) { goto Error; } sprintf(inputStreamName, "Input Stream #%ld", streamNum + 1); sprintf(outputStreamName, "Output Stream #%ld", streamNum + 1); if (!inputStream->initWithAudioEngine(this, kIOAudioStreamDirectionInput, startingChannelID, inputStreamName) || !outputStream->initWithAudioEngine(this, kIOAudioStreamDirectionOutput, startingChannelID, outputStreamName)) { goto Error; } formatIterator = OSCollectionIterator::withCollection(formatArray); if (!formatIterator) { goto Error; } sampleRateIterator = OSCollectionIterator::withCollection(sampleRateArray); if (!sampleRateIterator) { goto Error; } formatIterator->reset(); while (formatDict = (OSDictionary *)formatIterator->getNextObject()) { IOAudioStreamFormat format; if (OSDynamicCast(OSDictionary, formatDict) == NULL) { goto Error; } if (IOAudioStream::createFormatFromDictionary(formatDict, &format) == NULL) { goto Error; } if (!initialFormatSet) { initialFormat = format; } sampleRateIterator->reset(); while (number = (OSNumber *)sampleRateIterator->getNextObject()) { if (!OSDynamicCast(OSNumber, number)) { goto Error; } sampleRate.whole = number->unsigned32BitValue(); inputStream->addAvailableFormat(&format, &sampleRate, &sampleRate); if (format.fBitDepth == 24) { IOAudioStream::AudioIOFunction functions[2]; functions[0] = process24BitSamples; functions[1] = clip24BitSamples; //outputStream->addAvailableFormat(&format, &sampleRate, &sampleRate, functions, 2); outputStream->addAvailableFormat(&format, &sampleRate, &sampleRate, (IOAudioStream::AudioIOFunction)clip24BitSamples); if (format.fNumericRepresentation == kIOAudioStreamSampleFormatLinearPCM && format.fIsMixable == TRUE) { format.fIsMixable = FALSE; outputStream->addAvailableFormat(&format, &sampleRate, &sampleRate, (IOAudioStream::AudioIOFunction)clip24BitSamples); } } else if (format.fBitDepth == 16) { IOAudioStream::AudioIOFunction functions[2]; functions[0] = process16BitSamples; functions[1] = clip16BitSamples; //outputStream->addAvailableFormat(&format, &sampleRate, &sampleRate, functions, 2); outputStream->addAvailableFormat(&format, &sampleRate, &sampleRate, (IOAudioStream::AudioIOFunction)clip16BitSamples); if (format.fNumericRepresentation == kIOAudioStreamSampleFormatLinearPCM && format.fIsMixable == TRUE) { format.fIsMixable = FALSE; outputStream->addAvailableFormat(&format, &sampleRate, &sampleRate, (IOAudioStream::AudioIOFunction)clip24BitSamples); } } else { outputStream->addAvailableFormat(&format, &sampleRate, &sampleRate); if (format.fNumericRepresentation == kIOAudioStreamSampleFormatLinearPCM && format.fIsMixable == TRUE) { format.fIsMixable = FALSE; outputStream->addAvailableFormat(&format, &sampleRate, &sampleRate, (IOAudioStream::AudioIOFunction)clip24BitSamples); } } if (format.fNumChannels > maxNumChannels) { maxNumChannels = format.fNumChannels; } if (format.fBitWidth > maxBitWidth) { maxBitWidth = format.fBitWidth; } if (initialSampleRate->whole == 0) { initialSampleRate->whole = sampleRate.whole; } } } streamBufferSize = blockSize * numBlocks * maxNumChannels * maxBitWidth / 8; if (outputBuffer == NULL) { if (separateStreamBuffers) { outputBufferSize = streamBufferSize * numStreams; } else { outputBufferSize = streamBufferSize; } outputBuffer = (void *)IOMalloc(outputBufferSize); if (!outputBuffer) { IOLog("Error allocating output buffer - %lu bytes.\n", outputBufferSize); goto Error; } inputBufferSize = outputBufferSize; if (separateInputBuffers) { inputBuffer = (void *)IOMalloc(inputBufferSize); if (!inputBuffer) { IOLog("Error allocating input buffer - %lu bytes.\n", inputBufferSize); goto Error; } } else { inputBuffer = outputBuffer; } } inputStream->setFormat(&initialFormat); outputStream->setFormat(&initialFormat); if (separateStreamBuffers) { inputStream->setSampleBuffer(&((UInt8 *)inputBuffer)[streamBufferSize * streamNum], streamBufferSize); outputStream->setSampleBuffer(&((UInt8 *)outputBuffer)[streamBufferSize * streamNum], streamBufferSize); } else { inputStream->setSampleBuffer(inputBuffer, streamBufferSize); outputStream->setSampleBuffer(outputBuffer, streamBufferSize); } addAudioStream(inputStream); inputStream->release(); addAudioStream(outputStream); outputStream->release(); formatIterator->release(); sampleRateIterator->release(); for (channelID = startingChannelID; channelID < (startingChannelID + maxNumChannels); channelID++) { char channelName[20]; sprintf(channelName, "Channel %lu", channelID); control = IOAudioLevelControl::createVolumeControl(65535, 0, 65535, (-22 << 16) + (32768), 0, channelID, channelName, 0, kIOAudioControlUsageOutput); if (!control) { goto Error; } control->setValueChangeHandler((IOAudioControl::IntValueChangeHandler)PhantomAudioDevice::volumeChangeHandler, audioDevice); addDefaultAudioControl(control); control->release(); control = IOAudioToggleControl::createMuteControl(false, channelID, channelName, 0, kIOAudioControlUsageOutput); if (!control) { goto Error; } control->setValueChangeHandler((IOAudioControl::IntValueChangeHandler)PhantomAudioDevice::outputMuteChangeHandler, audioDevice); addDefaultAudioControl(control); control->release(); control = IOAudioLevelControl::createVolumeControl(65535, 0, 65535, (-22 << 16) + (32768), 0, channelID, channelName, 0, kIOAudioControlUsageInput); if (!control) { goto Error; } control->setValueChangeHandler((IOAudioControl::IntValueChangeHandler)PhantomAudioDevice::gainChangeHandler, audioDevice); addDefaultAudioControl(control); control->release(); control = IOAudioToggleControl::createMuteControl(false, channelID, channelName, 0, kIOAudioControlUsageInput); if (!control) { goto Error; } control->setValueChangeHandler((IOAudioControl::IntValueChangeHandler)PhantomAudioDevice::inputMuteChangeHandler, audioDevice); addDefaultAudioControl(control); control->release(); control = IOAudioToggleControl::createMuteControl(true, channelID, channelName, 0, kIOAudioControlUsagePassThru); if (!control) { goto Error; } control->setValueChangeHandler((IOAudioControl::IntValueChangeHandler)PhantomAudioDevice::passThruChangeHandler, audioDevice); addDefaultAudioControl(control); control->release(); } startingChannelID += maxNumChannels; continue; Error: IOLog("PhantomAudioEngine[%p]::createAudioStreams() - ERROR\n", this); if (inputStream) { inputStream->release(); } if (outputStream) { outputStream->release(); } if (formatIterator) { formatIterator->release(); } if (sampleRateIterator) { sampleRateIterator->release(); } goto Done; } control = IOAudioLevelControl::createVolumeControl(65535, 0, 65535, (-22 << 16) + (32768), 0, kIOAudioControlChannelIDAll, kIOAudioControlChannelNameAll, 0, kIOAudioControlUsageOutput); if (!control) { goto Done; } control->setValueChangeHandler((IOAudioControl::IntValueChangeHandler)PhantomAudioDevice::volumeChangeHandler, audioDevice); addDefaultAudioControl(control); control->release(); control = IOAudioToggleControl::createMuteControl(false, kIOAudioControlChannelIDAll, kIOAudioControlChannelNameAll, 0, kIOAudioControlUsageOutput); if (!control) { goto Done; } control->setValueChangeHandler((IOAudioControl::IntValueChangeHandler)PhantomAudioDevice::outputMuteChangeHandler, audioDevice); addDefaultAudioControl(control); control->release(); control = IOAudioLevelControl::createVolumeControl(65535, 0, 65535, (-22 << 16) + (32768), 0, kIOAudioControlChannelIDAll, kIOAudioControlChannelNameAll, 0, kIOAudioControlUsageInput); if (!control) { goto Done; } control->setValueChangeHandler((IOAudioControl::IntValueChangeHandler)PhantomAudioDevice::gainChangeHandler, audioDevice); addDefaultAudioControl(control); control->release(); control = IOAudioToggleControl::createMuteControl(false, kIOAudioControlChannelIDAll, kIOAudioControlChannelNameAll, 0, kIOAudioControlUsageInput); if (!control) { goto Done; } control->setValueChangeHandler((IOAudioControl::IntValueChangeHandler)PhantomAudioDevice::inputMuteChangeHandler, audioDevice); addDefaultAudioControl(control); control->release(); control = IOAudioToggleControl::createMuteControl(true, kIOAudioControlChannelIDAll, kIOAudioControlChannelNameAll, 0, kIOAudioControlUsagePassThru); if (!control) { goto Done; } control->setValueChangeHandler((IOAudioControl::IntValueChangeHandler)PhantomAudioDevice::passThruChangeHandler, audioDevice); addDefaultAudioControl(control); control->release(); result = true; Done: if (!result) { IOLog("PhantomAudioEngine[%p]::createAudioStreams() - failed!\n", this); } return result; }