Пример #1
0
/*
 * 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);
}
Пример #2
0
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;
}
Пример #3
0
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;
}
Пример #4
0
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;
}
Пример #5
0
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;
}
Пример #6
0
// 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;
}
Пример #7
0
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;
}