/* * Prepares an AVFormatContext for output. * Currently, the output format and codecs are hardcoded in this file. */ void Java_com_example_ffmpegtest_recorder_FFmpegWrapper_prepareAVFormatContext(JNIEnv *env, jobject obj, jstring jOutputPath){ init(); // Create AVRational that expects timestamps in microseconds videoSourceTimeBase = av_malloc(sizeof(AVRational)); videoSourceTimeBase->num = 1; videoSourceTimeBase->den = 1000000; audioSourceTimeBase = av_malloc(sizeof(AVRational)); audioSourceTimeBase->num = 1; audioSourceTimeBase->den = 1000000; AVFormatContext *inputFormatContext; outputPath = (*env)->GetStringUTFChars(env, jOutputPath, NULL); outputFormatContext = avFormatContextForOutputPath(outputPath, outputFormatName); LOGI("post avFormatContextForOutputPath"); // For copying AVFormatContext from sample file: /* inputFormatContext = avFormatContextForInputPath(sampleFilePath, outputFormatName); LOGI("post avFormatContextForInputPath"); copyAVFormatContext(&outputFormatContext, &inputFormatContext); LOGI("post copyAVFormatContext"); */ // For manually crafting AVFormatContext addVideoStream(outputFormatContext); addAudioStream(outputFormatContext); av_opt_set_int(outputFormatContext->priv_data, "hls_time", hlsSegmentDurationSec, 0); int result = openFileForWriting(outputFormatContext, outputPath); if(result < 0){ LOGE("openFileForWriting error: %d", result); } writeFileHeader(outputFormatContext); }
bool eqMac2DriverEngine::createAudioStreams(IOAudioSampleRate *initialSampleRate) { bool result = false; OSNumber* number = NULL; UInt32 numStreams; UInt32 streamNum; OSArray* formatArray = NULL; OSArray* sampleRateArray = NULL; UInt32 startingChannelID = 1; OSString* desc; 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) { IOLog("SF formatArray is NULL\n"); goto Done; } sampleRateArray = OSDynamicCast(OSArray, getProperty(SAMPLE_RATES_KEY)); if (sampleRateArray == NULL) { IOLog("SF sampleRateArray is NULL\n"); goto Done; } for (streamNum = 0; streamNum < numStreams; streamNum++) { UInt32 maxBitWidth = 0; UInt32 maxNumChannels = 0; OSCollectionIterator* formatIterator = NULL; OSCollectionIterator* sampleRateIterator = NULL; OSDictionary* formatDict; IOAudioSampleRate sampleRate; IOAudioStreamFormat initialFormat; bool initialFormatSet; UInt32 channelID; char outputStreamName[64]; char inputStreamName[64]; initialFormatSet = false; sampleRate.whole = 0; sampleRate.fraction = 0; inputStream = new IOAudioStream; if (inputStream == NULL) { IOLog("SF could not create new input IOAudioStream\n"); goto Error; } outputStream = new IOAudioStream; if (outputStream == NULL) { IOLog("SF could not create new output IOAudioStream\n"); goto Error; } snprintf(inputStreamName, 64, "eqMac2Driver Input Stream #%u", (unsigned int)streamNum + 1); snprintf(outputStreamName, 64, "eqMac2Driver Output Stream #%u", (unsigned int)streamNum + 1); if (!inputStream->initWithAudioEngine(this, kIOAudioStreamDirectionInput, startingChannelID, inputStreamName) || !outputStream->initWithAudioEngine(this, kIOAudioStreamDirectionOutput, startingChannelID, outputStreamName)) { IOLog("SF could not init one of the streams with audio engine. \n"); goto Error; } formatIterator = OSCollectionIterator::withCollection(formatArray); if (!formatIterator) { IOLog("SF NULL formatIterator\n"); goto Error; } sampleRateIterator = OSCollectionIterator::withCollection(sampleRateArray); if (!sampleRateIterator) { IOLog("SF NULL sampleRateIterator\n"); goto Error; } formatIterator->reset(); while ((formatDict = (OSDictionary *)formatIterator->getNextObject())) { IOAudioStreamFormat format; if (OSDynamicCast(OSDictionary, formatDict) == NULL) { IOLog("SF error casting formatDict\n"); goto Error; } if (IOAudioStream::createFormatFromDictionary(formatDict, &format) == NULL) { IOLog("SF error in createFormatFromDictionary()\n"); goto Error; } if (!initialFormatSet) { initialFormat = format; } sampleRateIterator->reset(); while ((number = (OSNumber *)sampleRateIterator->getNextObject())) { if (!OSDynamicCast(OSNumber, number)) { IOLog("SF error iterating sample rates\n"); goto Error; } sampleRate.whole = number->unsigned32BitValue(); inputStream->addAvailableFormat(&format, &sampleRate, &sampleRate); outputStream->addAvailableFormat(&format, &sampleRate, &sampleRate); if (format.fNumChannels > maxNumChannels) { maxNumChannels = format.fNumChannels; } if (format.fBitWidth > maxBitWidth) { maxBitWidth = format.fBitWidth; } if (initialSampleRate->whole == 0) { initialSampleRate->whole = sampleRate.whole; } } } mBufferSize = blockSize * numBlocks * maxNumChannels * maxBitWidth / 8; //IOLog("eqMac2Driver streamBufferSize: %ld\n", mBufferSize); if (mBuffer == NULL) { mBuffer = (void *)IOMalloc(mBufferSize); if (!mBuffer) { IOLog("eqMac2Driver: Error allocating output buffer - %lu bytes.\n", (unsigned long)mBufferSize); goto Error; } mThruBuffer = (float*)IOMalloc(mBufferSize); if (!mThruBuffer) { IOLog("eqMac2Driver: Error allocating thru buffer - %lu bytes.\n", (unsigned long)mBufferSize); goto Error; } memset((UInt8*)mThruBuffer, 0, mBufferSize); } inputStream->setFormat(&initialFormat); inputStream->setSampleBuffer(mBuffer, mBufferSize); addAudioStream(inputStream); inputStream->release(); outputStream->setFormat(&initialFormat); outputStream->setSampleBuffer(mBuffer, mBufferSize); addAudioStream(outputStream); outputStream->release(); formatIterator->release(); sampleRateIterator->release(); for (channelID = startingChannelID; channelID < (startingChannelID + maxNumChannels); channelID++) { char channelName[20]; snprintf(channelName, 20, "Channel %u", (unsigned int)channelID); } startingChannelID += maxNumChannels; continue; Error: IOLog("eqMac2DriverEngine[%p]::createAudioStreams() - ERROR\n", this); if (inputStream) inputStream->release(); if (outputStream) outputStream->release(); if (formatIterator) formatIterator->release(); if (sampleRateIterator) sampleRateIterator->release(); goto Done; } result = true; Done: if (!result) IOLog("eqMac2DriverEngine[%p]::createAudioStreams() - failed!\n", this); return result; }
bool PAEngine::initHardware(IOService *provider) { UInt32 sampleRates[] = SAMPLERATES; IOAudioSampleRate sampleRate; debugFunctionEnter(); device = OSDynamicCast(PADevice, provider); if (!device) return false; if (!super::initHardware(provider)) return false; virtualDeviceArray = OSArray::withCapacity(1); if (!virtualDeviceArray) { IOLog("%s(%p)::%s unable to allocate memory\n", getName(), this, __func__); return false; } sampleRate.whole = sampleRates[0]; sampleRate.fraction = 0; setSampleRate(&sampleRate); setNewSampleRate(sampleRate.whole); setDescription(info->name); setNumSampleFramesPerBuffer(NUM_SAMPLE_FRAMES); info->audioBufferSize = AUDIO_BUFFER_SIZE * nStreams; audioInBuf = IOBufferMemoryDescriptor::withCapacity(info->audioBufferSize, kIODirectionInOut); audioOutBuf = IOBufferMemoryDescriptor::withCapacity(info->audioBufferSize, kIODirectionInOut); if (!audioInBuf || !audioOutBuf) { IOLog("%s(%p)::%s unable to allocate memory\n", getName(), this, __func__); return false; } audioInBuf->prepare(); audioOutBuf->prepare(); for (UInt32 i = 0; i < nStreams; i++) { IOAudioStream *stream; char *streamBuf; if (i * CHANNELS_PER_STREAM < channelsIn) { streamBuf = (char *) audioInBuf->getBytesNoCopy() + (i * AUDIO_BUFFER_SIZE); stream = createNewAudioStream(kIOAudioStreamDirectionInput, streamBuf); if (!stream) { IOLog("%s(%p)::%s failed to create audio streams\n", getName(), this, __func__); return false; } addAudioStream(stream); audioStream[i * 2] = stream; stream->release(); } if (i * CHANNELS_PER_STREAM < channelsOut) { streamBuf = (char *) audioOutBuf->getBytesNoCopy() + (i * AUDIO_BUFFER_SIZE); stream = createNewAudioStream(kIOAudioStreamDirectionOutput, streamBuf); if (!stream) { IOLog("%s(%p)::%s failed to create audio streams\n", getName(), this, __func__); return false; } addAudioStream(stream); audioStream[(i * 2) + 1] = stream; stream->release(); } } if (info->audioContentType == kPADeviceAudioContentMixdown) return addVirtualDevice(info, audioInBuf, audioOutBuf, this) == kIOReturnSuccess; return true; }
bool kXAudioEngine::initHardware(IOService *provider) { bool result = false; IOAudioSampleRate initialSampleRate; IOAudioStream *audioStream; debug("kXAudioEngine[%p]::initHardware(%p)\n", this, provider); if (!super::initHardware(provider)) { goto Done; } // Setup the initial sample rate for the audio engine initialSampleRate.whole = sampling_rate; initialSampleRate.fraction = 0; char device_name[KX_MAX_STRING]; strncpy(device_name,"kX ",KX_MAX_STRING); strncat(device_name,hw->card_name,KX_MAX_STRING); setDescription(device_name); setSampleRate(&initialSampleRate); setClockDomain(); // =kIOAudioNewClockDomain // calculate kx_sample_offset if(hw->is_10k2) { // setSampleOffset(28); // 28 samples setSampleLatency(28+1); } else { // setSampleOffset(32); // 32 samples setSampleLatency(32+1); } // Allocate our input and output buffers for(int i=0;i<n_channels;i++) { // Create an IOAudioStream for each buffer and add it to this audio engine audioStream = createNewAudioStream(i,kIOAudioStreamDirectionOutput, 1*n_frames*bps/8); if (!audioStream) { goto Done; } addAudioStream(audioStream); out_streams[i]=audioStream; } // recording audioStream = createNewAudioStream(0,kIOAudioStreamDirectionInput, n_channels*n_frames*bps/8); if (!audioStream) { goto Done; } addAudioStream(audioStream); in_streams[0]=audioStream; dump_addr(); // Set the number of sample frames in each buffer setNumSampleFramesPerBuffer(n_frames); result = true; Done: if(result==false) free_all(); return result; }
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; }
// setup libAV related structs. bool AV::setupAV() { ct.of = av_guess_format(NULL, "roxlu.flv", NULL); if(!ct.of) { printf("Cannot create flv AVOutputFormat\n"); return false; } ct.c = avformat_alloc_context(); if(!ct.c) { printf("Cannot allocate the AVFormatContext\n"); return false; } ct.c->video_codec_id = CODEC_ID_H264; ct.c->debug = 3; ct.c->oformat = ct.of; // const char* output_filename = "tcp://127.0.0.1:6665"; // const char* output_filename = "rtmp://gethinlewis.rtmphost.com"; const char* output_filename = "rtmp://gethinlewis.rtmphost.com/event/_definst_"; // const char* output_filename = "test.flv"; snprintf(ct.c->filename, sizeof(ct.c->filename), "%s", output_filename); //ct.vs = addVideoStream(ct, ct.of->video_codec); printf("%d -- %d \n", CODEC_ID_H264, ct.of->video_codec); ct.of->video_codec = CODEC_ID_H264; ct.vs = addVideoStream(ct, ct.of->video_codec); if(!ct.vs) { printf("Cannot create video stream: %d.\n", ct.of->video_codec); return false; } if(!openVideo(ct)) { printf("Cannot open video stream.\n"); return false; } //av_dict_set(&ct.c->metadata, "streamName", "video_test", 0); av_dict_set(&ct.c->metadata, "streamName", "livefeed", 0); if(use_audio) { bool use_mp3 = true; if(!use_mp3) { ct.asample_fmt = AV_SAMPLE_FMT_S16; ct.abit_rate = 64000; ct.asample_rate = 8000; ct.as = addAudioStream(ct, CODEC_ID_SPEEX); } else { ct.asample_fmt = AV_SAMPLE_FMT_S16; ct.abit_rate = 64000; ct.asample_rate = 44100; ct.as = addAudioStream(ct, CODEC_ID_MP3); } if(!ct.as) { printf("Cannot create audio stream.\n"); return false; } if(!openAudio(ct)) { printf("Cannot open audio stream.\n"); return false; } } av_dump_format(ct.c, 0, output_filename, 1); if(!(ct.of->flags & AVFMT_NOFILE)) { if(avio_open(&ct.c->pb, output_filename, AVIO_FLAG_WRITE) < 0) { printf("Cannot open: %s\n", output_filename); return false; } } avformat_write_header(ct.c, NULL); return true; }
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; }