/*---------------------------------------------------------------------- | OsxAudioUnitsOutput_Seek +---------------------------------------------------------------------*/ BLT_METHOD OsxAudioUnitsOutput_Seek(BLT_MediaNode* _self, BLT_SeekMode* mode, BLT_SeekPoint* point) { OsxAudioUnitsOutput* self = ATX_SELF_EX(OsxAudioUnitsOutput, BLT_BaseMediaNode, BLT_MediaNode); ComponentResult result; BLT_COMPILER_UNUSED(mode); BLT_COMPILER_UNUSED(point); /* flush the queue */ pthread_mutex_lock(&self->lock); ATX_List_Clear(self->packet_queue); pthread_mutex_unlock(&self->lock); /* reset the device */ result = AudioUnitReset(self->audio_unit, kAudioUnitScope_Input, 0); if (result != noErr) { ATX_LOG_WARNING_1("AudioUnitReset failed (%d)", (int)result); } return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | OsxAudioUnitsOutput_Destroy +---------------------------------------------------------------------*/ static BLT_Result OsxAudioUnitsOutput_Destroy(OsxAudioUnitsOutput* self) { /* drain the queue */ OsxAudioUnitsOutput_Drain(&ATX_BASE(self, BLT_OutputNode)); /* stop the audio pump */ OsxAudioUnitsOutput_Stop(&ATX_BASE_EX(self, BLT_BaseMediaNode, BLT_MediaNode)); /* close the audio unit */ if (self->audio_unit) { ComponentResult result; result = CloseComponent(self->audio_unit); if (result != noErr) { ATX_LOG_WARNING_1("CloseComponent failed (%d)", (int)result); } } /* destroy the queue */ ATX_List_Destroy(self->packet_queue); /* destroy the lock */ pthread_mutex_destroy(&self->lock); /* destruct the inherited object */ BLT_BaseMediaNode_Destruct(&ATX_BASE(self, BLT_BaseMediaNode)); /* free the object memory */ ATX_FreeMemory(self); return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | BLT_TcpNetworkStream_Create +---------------------------------------------------------------------*/ BLT_Result BLT_TcpNetworkStream_Create(const char* name, ATX_InputStream** stream) { ATX_Socket* sock; ATX_String hostname = ATX_String_Create(name); ATX_UInt16 port = BLT_TCP_NETWORK_STREAM_DEFAULT_PORT; int sep; ATX_Result result = ATX_SUCCESS; /* default */ *stream = NULL; /* parse the hostname/port */ sep = ATX_String_FindCharFrom(&hostname, ':', 6); if (sep > 0) { /* we have a port number */ int port_long = 0; result = ATX_ParseInteger(name+sep+1, &port_long, ATX_FALSE); if (ATX_FAILED(result)) { ATX_LOG_WARNING("BLT_TcpNetworkStream_Create - invalid port spec"); goto end; } port = (ATX_UInt16)port_long; ATX_String_SetLength(&hostname, sep); } /* create a socket */ result = ATX_TcpClientSocket_Create(&sock); if (ATX_FAILED(result)) goto end; /* connect */ ATX_LOG_FINE_2("BLT_TcpNetworkStream_Create - connecting to %s:%d", ATX_CSTR(hostname), port); result = ATX_Socket_ConnectToHost(sock, ATX_CSTR(hostname), port, BLT_TCP_NETWORK_STREAM_DEFAULT_TIMEOUT); if (ATX_FAILED(result)) { ATX_LOG_WARNING_1("BLT_TcpNetworkStream_Create - failed to connect (%d)", result); goto end; } ATX_LOG_FINE("BLT_TcpNetworkStream_Create - connected"); /* return the input stream */ result = ATX_Socket_GetInputStream(sock, stream); /* release the socket */ ATX_DESTROY_OBJECT(sock); end: ATX_String_Destruct(&hostname); return result; }
/*---------------------------------------------------------------------- | OsxAudioUnitsOutput_Start +---------------------------------------------------------------------*/ BLT_METHOD OsxAudioUnitsOutput_Start(BLT_MediaNode* _self) { OsxAudioUnitsOutput* self = ATX_SELF_EX(OsxAudioUnitsOutput, BLT_BaseMediaNode, BLT_MediaNode); ComponentResult result; /* start the audio unit */ result = AudioOutputUnitStart(self->audio_unit); if (result != noErr) { ATX_LOG_WARNING_1("AudioUnitOutputStart failed (%d)", (int)result); } return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | OsxAudioUnitsOutput_Stop +---------------------------------------------------------------------*/ BLT_METHOD OsxAudioUnitsOutput_Stop(BLT_MediaNode* _self) { OsxAudioUnitsOutput* self = ATX_SELF_EX(OsxAudioUnitsOutput, BLT_BaseMediaNode, BLT_MediaNode); ComponentResult result; /* flush the queue */ pthread_mutex_lock(&self->lock); ATX_List_Clear(self->packet_queue); pthread_mutex_unlock(&self->lock); /* stop the and reset audio unit */ result = AudioOutputUnitStop(self->audio_unit); if (result != noErr) { ATX_LOG_WARNING_1("AudioUnitOutputStop failed (%d)", (int)result); } result = AudioUnitReset(self->audio_unit, kAudioUnitScope_Input, 0); if (result != noErr) { ATX_LOG_WARNING_1("AudioUnitReset failed (%d)", (int)result); } return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | OsxAudioUnitsOutput_Resume +---------------------------------------------------------------------*/ BLT_METHOD OsxAudioUnitsOutput_Resume(BLT_MediaNode* _self) { OsxAudioUnitsOutput* self = ATX_SELF_EX(OsxAudioUnitsOutput, BLT_BaseMediaNode, BLT_MediaNode); ComponentResult result; if (self->paused) { ATX_LOG_FINE("resuming output"); self->paused = BLT_FALSE; result = AudioOutputUnitStart(self->audio_unit); if (result != noErr) { ATX_LOG_WARNING_1("AudioUnitOutputStart failed (%d)", (int)result); } } return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | PcmAdapterInput_PutPacket +---------------------------------------------------------------------*/ BLT_METHOD PcmAdapterInput_PutPacket(BLT_PacketConsumer* _self, BLT_MediaPacket* packet) { PcmAdapter* self = ATX_SELF_M(input, PcmAdapter, BLT_PacketConsumer); BLT_Result result; /* transform the packet data */ result = BLT_Pcm_ConvertMediaPacket(ATX_BASE(self, BLT_BaseMediaNode).core, packet, &self->output.pcm_type, &self->output.packet); if (BLT_FAILED(result)) { ATX_LOG_WARNING_1("PcmAdapterInput::PutPacket - failed to convert PCM (%d)", result); } return result; }
/*---------------------------------------------------------------------- | OsxAudioUnitsOutput_Deactivate +---------------------------------------------------------------------*/ BLT_METHOD OsxAudioUnitsOutput_Deactivate(BLT_MediaNode* _self) { OsxAudioUnitsOutput* self = ATX_SELF_EX(OsxAudioUnitsOutput, BLT_BaseMediaNode, BLT_MediaNode); ComponentResult result; ATX_LOG_FINER("OsxAudioUnitsOutput::Deactivate"); /* un-initialize the device */ if (self->audio_unit) { result = AudioUnitUninitialize(self->audio_unit); if (result != noErr) { ATX_LOG_WARNING_1("AudioUnitUninitialize failed (%d)", (int)result); return BLT_FAILURE; } } return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | AlsaOutput_Write +---------------------------------------------------------------------*/ static BLT_Result AlsaOutput_Write(AlsaOutput* self, void* buffer, BLT_Size size) { int watchdog = 5; int io_result; unsigned int sample_count; unsigned int sample_size; BLT_Result result; /* ensure that the device is prepared */ result = AlsaOutput_Prepare(self); if (BLT_FAILED(result)) return result; /* compute the number of samples */ sample_size = self->media_type.channel_count*self->media_type.bits_per_sample/8; sample_count = size / sample_size; /* write samples to the device and handle underruns */ do { while (sample_count) { io_result = snd_pcm_writei(self->device_handle, buffer, sample_count); if (io_result > 0) { buffer = (void*)((char*)buffer + io_result*sample_size); if ((unsigned int)io_result <= sample_count) { sample_count -= io_result; } else { /* strange, snd_pcm_writei returned more than we wrote */ sample_count = 0; } } else { break; } } if (sample_count == 0) return BLT_SUCCESS; /* we reach this point if the first write failed */ if (io_result < 0) { snd_pcm_status_t* status; snd_pcm_state_t state; snd_pcm_status_alloca_no_assert(&status); io_result = snd_pcm_status(self->device_handle, status); if (io_result != 0) { return BLT_FAILURE; } state = snd_pcm_status_get_state(status); if (state == SND_PCM_STATE_XRUN) { ATX_LOG_FINE("**** UNDERRUN *****"); /* re-prepare the channel */ io_result = snd_pcm_prepare(self->device_handle); if (io_result != 0) { return BLT_FAILURE; } } else { ATX_LOG_WARNING_1("**** STATE = %d ****", state); } } else { ATX_LOG_WARNING_1("snd_pcm_writei() returned %d", io_result); } ATX_LOG_FINE("**** RETRY *****"); } while(watchdog--); ATX_LOG_SEVERE("**** THE WATCHDOG BIT US ****"); return BLT_FAILURE; }
/*---------------------------------------------------------------------- | Mp4Parser_Seek +---------------------------------------------------------------------*/ BLT_METHOD Mp4Parser_Seek(BLT_MediaNode* _self, BLT_SeekMode* mode, BLT_SeekPoint* point) { Mp4Parser* self = ATX_SELF_EX(Mp4Parser, BLT_BaseMediaNode, BLT_MediaNode); /* estimate the seek point */ if (ATX_BASE(self, BLT_BaseMediaNode).context == NULL) return BLT_FAILURE; BLT_Stream_EstimateSeekPoint(ATX_BASE(self, BLT_BaseMediaNode).context, *mode, point); if (!(point->mask & BLT_SEEK_POINT_MASK_TIME_STAMP)) { return BLT_FAILURE; } /* seek to the estimated offset on all tracks */ AP4_Ordinal sample_index = 0; AP4_UI32 ts_ms = point->time_stamp.seconds*1000+point->time_stamp.nanoseconds/1000000; if (self->video_output.track) { AP4_Result result = self->video_output.track->GetSampleIndexForTimeStampMs(ts_ms, sample_index); if (AP4_FAILED(result)) { ATX_LOG_WARNING_1("video GetSampleIndexForTimeStampMs failed (%d)", result); return BLT_FAILURE; } ATX_LOG_FINE_1("seeking to video time %d ms", ts_ms); // go to the nearest sync sample self->video_output.sample = self->video_output.track->GetNearestSyncSampleIndex(sample_index); if (self->input.reader) { self->input.reader->SetSampleIndex(self->video_output.track->GetId(), self->video_output.sample); } ATX_LOG_FINE_1("seeking to video sync sample %d", self->video_output.sample); // compute the timestamp of the video sample we're seeking to, so we can pick an audio // sample that is close in time (there are many more audio sync points than video) AP4_Sample sample; if (AP4_SUCCEEDED(self->video_output.track->GetSample(self->video_output.sample, sample))) { AP4_UI32 media_timescale = self->video_output.track->GetMediaTimeScale(); if (media_timescale) { ts_ms = (AP4_UI32)((((AP4_UI64)sample.GetCts())*1000)/media_timescale); ATX_LOG_FINE_1("sync sample time is %d ms", ts_ms); } } else { ATX_LOG_FINE_1("unable to get sample info for sample %d", self->video_output.sample); } } if (self->audio_output.track) { AP4_Result result = self->audio_output.track->GetSampleIndexForTimeStampMs(ts_ms, sample_index); if (AP4_FAILED(result)) { ATX_LOG_WARNING_1("audio GetSampleIndexForTimeStampMs failed (%d)", result); return BLT_FAILURE; } self->audio_output.sample = sample_index; if (self->input.reader) { self->input.reader->SetSampleIndex(self->audio_output.track->GetId(), sample_index); } } /* set the mode so that the nodes down the chain know the seek has */ /* already been done on the stream */ *mode = BLT_SEEK_MODE_IGNORE; return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | Mp4ParserOutput_GetPacket +---------------------------------------------------------------------*/ BLT_METHOD Mp4ParserOutput_GetPacket(BLT_PacketProducer* _self, BLT_MediaPacket** packet) { Mp4ParserOutput* self = ATX_SELF(Mp4ParserOutput, BLT_PacketProducer); *packet = NULL; // if we don't have an input yet, we can't produce packets //if (self->parser->input.mp4_file == NULL) { // return BLT_ERROR_PORT_HAS_NO_DATA; //} if (self->track == NULL) { return BLT_ERROR_EOS; } else { // check for end-of-stream if (self->sample >= self->track->GetSampleCount()) { return BLT_ERROR_EOS; } // read one sample AP4_Sample sample; AP4_DataBuffer* sample_buffer = self->sample_buffer; AP4_Result result; if (self->parser->input.reader) { // linear reader mode result = self->parser->input.reader->ReadNextSample(self->track->GetId(), sample, *sample_buffer); if (AP4_SUCCEEDED(result)) self->sample++; } else { // normal mode result = self->track->ReadSample(self->sample++, sample, *sample_buffer); } if (AP4_FAILED(result)) { ATX_LOG_WARNING_1("ReadSample failed (%d)", result); if (result == AP4_ERROR_EOS || result == ATX_ERROR_OUT_OF_RANGE) { ATX_LOG_WARNING("incomplete media"); return BLT_ERROR_INCOMPLETE_MEDIA; } else { return BLT_ERROR_PORT_HAS_NO_DATA; } } // update the sample description if it has changed if (sample.GetDescriptionIndex() != self->sample_description_index) { result = Mp4ParserOutput_SetSampleDescription(self, sample.GetDescriptionIndex()); if (BLT_FAILED(result)) return result; } // decrypt the sample if needed if (self->sample_decrypter) { self->sample_decrypter->DecryptSampleData(*sample_buffer, *self->sample_decrypted_buffer); sample_buffer = self->sample_decrypted_buffer; } AP4_Size packet_size = sample_buffer->GetDataSize(); result = BLT_Core_CreateMediaPacket(ATX_BASE(self->parser, BLT_BaseMediaNode).core, packet_size, (const BLT_MediaType*)self->media_type, packet); if (BLT_FAILED(result)) return result; BLT_MediaPacket_SetPayloadSize(*packet, packet_size); void* buffer = BLT_MediaPacket_GetPayloadBuffer(*packet); ATX_CopyMemory(buffer, sample_buffer->GetData(), packet_size); // set the timestamp AP4_UI32 media_timescale = self->track->GetMediaTimeScale(); if (media_timescale) { AP4_UI64 ts = ((AP4_UI64)sample.GetCts())*1000000; ts /= media_timescale; BLT_TimeStamp bt_ts = { (BLT_Int32)(ts / 1000000), (BLT_Int32)((ts % 1000000)*1000) }; BLT_MediaPacket_SetTimeStamp(*packet, bt_ts); } // set packet flags if (self->sample == 1) { BLT_MediaPacket_SetFlags(*packet, BLT_MEDIA_PACKET_FLAG_START_OF_STREAM); } return BLT_SUCCESS; } }
/*---------------------------------------------------------------------- | OsxAudioUnitsOutput_Create +---------------------------------------------------------------------*/ static BLT_Result OsxAudioUnitsOutput_Create(BLT_Module* module, BLT_Core* core, BLT_ModuleParametersType parameters_type, const void* parameters, BLT_MediaNode** object) { OsxAudioUnitsOutput* self; BLT_MediaNodeConstructor* constructor = (BLT_MediaNodeConstructor*)parameters; AudioDeviceID audio_device_id = 0; AudioUnit audio_unit = NULL; Component component; ComponentDescription component_desc; ComponentResult result; BLT_Result blt_result; /* check parameters */ if (parameters == NULL || parameters_type != BLT_MODULE_PARAMETERS_TYPE_MEDIA_NODE_CONSTRUCTOR) { return BLT_ERROR_INVALID_PARAMETERS; } /* parse the name */ if (!ATX_StringsEqualN(constructor->name, "osxau:", 6)) { return BLT_ERROR_INTERNAL; } /* map the name into a device ID */ blt_result = OsxAudioUnitsOutput_MapDeviceName(constructor->name+6, &audio_device_id); if (BLT_FAILED(blt_result)) return blt_result; /* get the default output audio unit */ ATX_SetMemory(&component_desc, 0, sizeof(component_desc)); component_desc.componentType = kAudioUnitType_Output; component_desc.componentSubType = audio_device_id?kAudioUnitSubType_HALOutput:kAudioUnitSubType_DefaultOutput; component_desc.componentManufacturer = kAudioUnitManufacturer_Apple; component_desc.componentFlags = 0; component_desc.componentFlagsMask = 0; component = FindNextComponent(NULL, &component_desc); if (component == NULL) { ATX_LOG_WARNING("FindNextComponent failed"); return BLT_FAILURE; } /* open the audio unit (we will initialize it later) */ result = OpenAComponent(component, &audio_unit); if (result != noErr) { ATX_LOG_WARNING_1("OpenAComponent failed (%d)", (int)result); return BLT_FAILURE; } /* Since SnowLeopard, kAudioHardwarePropertyRunLoop points at the process's main thread. Since not all apps service a run loop on the main thread (like command-line apps), we need to set the run loop to NULL to tell the HAL to run its own thread for this. This is important in order for the HAL to receive events when, for example, the headphones are plugged in or out. NOTE: this was the default before SnowLeopard (10.6), so we only do this if we're 10.6 or after */ { SInt32 major, minor; Gestalt(gestaltSystemVersionMajor, &major); Gestalt(gestaltSystemVersionMinor, &minor); if (major > 10 || (major == 10 && minor >= 6)) { ATX_LOG_INFO("configuring the HAL to use its own thread for the run loop"); CFRunLoopRef null_loop = NULL; AudioObjectPropertyAddress address = { kAudioHardwarePropertyRunLoop, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; AudioObjectSetPropertyData(kAudioObjectSystemObject, &address, 0, NULL, sizeof(CFRunLoopRef), &null_loop); } } /* allocate memory for the object */ self = ATX_AllocateZeroMemory(sizeof(OsxAudioUnitsOutput)); if (self == NULL) { *object = NULL; return BLT_ERROR_OUT_OF_MEMORY; } /* construct the inherited object */ BLT_BaseMediaNode_Construct(&ATX_BASE(self, BLT_BaseMediaNode), module, core); /* construct the object */ self->audio_device_id = audio_device_id; self->audio_unit = audio_unit; self->media_type.sample_rate = 0; self->media_type.channel_count = 0; self->media_type.bits_per_sample = 0; /* create a lock */ pthread_mutex_init(&self->lock, NULL); /* create the packet queue */ { ATX_ListDataDestructor destructor = { NULL, OsxAudioUnitsOutput_QueueItemDestructor }; ATX_List_CreateEx(&destructor, &self->packet_queue); self->max_packets_in_queue = BLT_OSX_AUDIO_UNITS_OUTPUT_DEFAULT_PACKET_QUEUE_SIZE; } /* setup the expected media type */ BLT_PcmMediaType_Init(&self->expected_media_type); self->expected_media_type.sample_format = BLT_PCM_SAMPLE_FORMAT_SIGNED_INT_NE; /* setup interfaces */ ATX_SET_INTERFACE_EX(self, OsxAudioUnitsOutput, BLT_BaseMediaNode, BLT_MediaNode); ATX_SET_INTERFACE_EX(self, OsxAudioUnitsOutput, BLT_BaseMediaNode, ATX_Referenceable); ATX_SET_INTERFACE (self, OsxAudioUnitsOutput, BLT_PacketConsumer); ATX_SET_INTERFACE (self, OsxAudioUnitsOutput, BLT_OutputNode); ATX_SET_INTERFACE (self, OsxAudioUnitsOutput, BLT_MediaPort); ATX_SET_INTERFACE (self, OsxAudioUnitsOutput, BLT_VolumeControl); *object = &ATX_BASE_EX(self, BLT_BaseMediaNode, BLT_MediaNode); return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | OsxAudioUnitsOutput_SetStreamFormat +---------------------------------------------------------------------*/ static BLT_Result OsxAudioUnitsOutput_SetStreamFormat(OsxAudioUnitsOutput* self, const BLT_PcmMediaType* media_type) { OSStatus result; AudioStreamBasicDescription audio_desc; /* setup the audio description */ audio_desc.mFormatID = kAudioFormatLinearPCM; audio_desc.mFormatFlags = kAudioFormatFlagIsPacked; audio_desc.mFramesPerPacket = 1; audio_desc.mSampleRate = media_type->sample_rate; audio_desc.mChannelsPerFrame = media_type->channel_count; audio_desc.mBitsPerChannel = media_type->bits_per_sample; audio_desc.mBytesPerFrame = (audio_desc.mBitsPerChannel * audio_desc.mChannelsPerFrame) / 8; audio_desc.mBytesPerPacket = audio_desc.mBytesPerFrame * audio_desc.mFramesPerPacket; audio_desc.mReserved = 0; /* select the sample format */ switch (media_type->sample_format) { case BLT_PCM_SAMPLE_FORMAT_UNSIGNED_INT_BE: audio_desc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; break; case BLT_PCM_SAMPLE_FORMAT_UNSIGNED_INT_LE: break; case BLT_PCM_SAMPLE_FORMAT_SIGNED_INT_BE: audio_desc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger; audio_desc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; break; case BLT_PCM_SAMPLE_FORMAT_SIGNED_INT_LE: audio_desc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger; break; case BLT_PCM_SAMPLE_FORMAT_FLOAT_BE: audio_desc.mFormatFlags |= kLinearPCMFormatFlagIsFloat; audio_desc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; break; case BLT_PCM_SAMPLE_FORMAT_FLOAT_LE: audio_desc.mFormatFlags |= kLinearPCMFormatFlagIsFloat; break; default: return BLT_ERROR_INVALID_MEDIA_TYPE; } /* drain any pending packets before we switch */ result = OsxAudioUnitsOutput_Drain(&ATX_BASE(self, BLT_OutputNode)); if (BLT_FAILED(result)) return result; /* set the audio unit property */ result = AudioUnitSetProperty(self->audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &audio_desc, sizeof(audio_desc)); if (result != noErr) { ATX_LOG_WARNING_1("AudioUnitSetProperty failed (%d)", (int)result); return BLT_FAILURE; } /* copy the format */ self->media_type = *media_type; return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | OsxAudioUnitsOutput_Activate +---------------------------------------------------------------------*/ BLT_METHOD OsxAudioUnitsOutput_Activate(BLT_MediaNode* _self, BLT_Stream* stream) { OsxAudioUnitsOutput* self = ATX_SELF_EX(OsxAudioUnitsOutput, BLT_BaseMediaNode, BLT_MediaNode); ComponentResult result; AURenderCallbackStruct callback; BLT_COMPILER_UNUSED(stream); ATX_LOG_FINER("start"); /* select the device */ if (self->audio_device_id) { result = AudioUnitSetProperty(self->audio_unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &self->audio_device_id, sizeof(self->audio_device_id)); if (result != noErr) { ATX_LOG_WARNING_1("AudioUnitSetProperty (kAudioOutputUnitProperty_CurrentDevice) failed (%d)", (int)result); } } /* initialize the output */ if (self->audio_unit) { result = AudioUnitInitialize(self->audio_unit); if (result != noErr) { ATX_LOG_WARNING_1("AudioUnitInitialize failed (%d)", (int)result); return BLT_FAILURE; } } /* set some default audio format */ { AudioStreamBasicDescription audio_desc; ATX_SetMemory(&audio_desc, 0, sizeof(audio_desc)); /* setup the audio description */ audio_desc.mFormatID = kAudioFormatLinearPCM; audio_desc.mFormatFlags = kAudioFormatFlagsNativeEndian | kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; audio_desc.mFramesPerPacket = 1; audio_desc.mSampleRate = 44100; audio_desc.mChannelsPerFrame = 2; audio_desc.mBitsPerChannel = 16; audio_desc.mBytesPerFrame = (audio_desc.mBitsPerChannel * audio_desc.mChannelsPerFrame) / 8; audio_desc.mBytesPerPacket = audio_desc.mBytesPerFrame * audio_desc.mFramesPerPacket; audio_desc.mReserved = 0; result = AudioUnitSetProperty(self->audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &audio_desc, sizeof(audio_desc)); if (result != noErr) { ATX_LOG_WARNING_1("AudioUnitSetProperty failed (%d)", (int)result); return BLT_FAILURE; } } /* check for downmix based on the number of supported channels */ OsxAudioUnitsOutput_CheckDownmix(self); /* setup the callback */ callback.inputProc = OsxAudioUnitsOutput_RenderCallback; callback.inputProcRefCon = _self; result = AudioUnitSetProperty(self->audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &callback, sizeof(callback)); if (result != noErr) { ATX_LOG_SEVERE_1("AudioUnitSetProperty failed when setting callback (%d)", (int)result); return BLT_FAILURE; } return BLT_SUCCESS; }