static int init(int rate,int channels,int format,int flags) { AudioStreamBasicDescription inDesc; ComponentDescription desc; Component comp; AURenderCallbackStruct renderCallback; OSStatus err; UInt32 size, maxFrames, b_alive; char *psz_name; AudioDeviceID devid_def = 0; int device_id, display_help = 0; const opt_t subopts[] = { {"device_id", OPT_ARG_INT, &device_id, NULL}, {"help", OPT_ARG_BOOL, &display_help, NULL}, {NULL} }; // set defaults device_id = 0; if (subopt_parse(ao_subdevice, subopts) != 0 || display_help) { print_help(); if (!display_help) return 0; } ao_msg(MSGT_AO,MSGL_V, "init([%dHz][%dch][%s][%d])\n", rate, channels, af_fmt2str_short(format), flags); ao = calloc(1, sizeof(ao_coreaudio_t)); ao->i_selected_dev = 0; ao->b_supports_digital = 0; ao->b_digital = 0; ao->b_muted = 0; ao->b_stream_format_changed = 0; ao->i_hog_pid = -1; ao->i_stream_id = 0; ao->i_stream_index = -1; ao->b_revert = 0; ao->b_changed_mixing = 0; if (device_id == 0) { /* Find the ID of the default Device. */ err = GetAudioProperty(kAudioObjectSystemObject, kAudioHardwarePropertyDefaultOutputDevice, sizeof(UInt32), &devid_def); if (err != noErr) { ao_msg(MSGT_AO, MSGL_WARN, "could not get default audio device: [%4.4s]\n", (char *)&err); goto err_out; } } else { devid_def = device_id; } /* Retrieve the name of the device. */ err = GetAudioPropertyString(devid_def, kAudioObjectPropertyName, &psz_name); if (err != noErr) { ao_msg(MSGT_AO, MSGL_WARN, "could not get default audio device name: [%4.4s]\n", (char *)&err); goto err_out; } ao_msg(MSGT_AO,MSGL_V, "got audio output device ID: %"PRIu32" Name: %s\n", devid_def, psz_name ); /* Probe whether device support S/PDIF stream output if input is AC3 stream. */ if (AF_FORMAT_IS_AC3(format)) { if (AudioDeviceSupportsDigital(devid_def)) { ao->b_supports_digital = 1; } ao_msg(MSGT_AO, MSGL_V, "probe default audio output device about support for digital s/pdif output: %d\n", ao->b_supports_digital ); } free(psz_name); // Save selected device id ao->i_selected_dev = devid_def; // Build Description for the input format inDesc.mSampleRate=rate; inDesc.mFormatID=ao->b_supports_digital ? kAudioFormat60958AC3 : kAudioFormatLinearPCM; inDesc.mChannelsPerFrame=channels; inDesc.mBitsPerChannel=af_fmt2bits(format); if((format&AF_FORMAT_POINT_MASK)==AF_FORMAT_F) { // float inDesc.mFormatFlags = kAudioFormatFlagIsFloat|kAudioFormatFlagIsPacked; } else if((format&AF_FORMAT_SIGN_MASK)==AF_FORMAT_SI) { // signed int inDesc.mFormatFlags = kAudioFormatFlagIsSignedInteger|kAudioFormatFlagIsPacked; } else { // unsigned int inDesc.mFormatFlags = kAudioFormatFlagIsPacked; } if ((format & AF_FORMAT_END_MASK) == AF_FORMAT_BE) inDesc.mFormatFlags |= kAudioFormatFlagIsBigEndian; inDesc.mFramesPerPacket = 1; ao->packetSize = inDesc.mBytesPerPacket = inDesc.mBytesPerFrame = inDesc.mFramesPerPacket*channels*(inDesc.mBitsPerChannel/8); print_format(MSGL_V, "source:",&inDesc); if (ao->b_supports_digital) { b_alive = 1; err = GetAudioProperty(ao->i_selected_dev, kAudioDevicePropertyDeviceIsAlive, sizeof(UInt32), &b_alive); if (err != noErr) ao_msg(MSGT_AO, MSGL_WARN, "could not check whether device is alive: [%4.4s]\n", (char *)&err); if (!b_alive) ao_msg(MSGT_AO, MSGL_WARN, "device is not alive\n" ); /* S/PDIF output need device in HogMode. */ err = GetAudioProperty(ao->i_selected_dev, kAudioDevicePropertyHogMode, sizeof(pid_t), &ao->i_hog_pid); if (err != noErr) { /* This is not a fatal error. Some drivers simply don't support this property. */ ao_msg(MSGT_AO, MSGL_WARN, "could not check whether device is hogged: [%4.4s]\n", (char *)&err); ao->i_hog_pid = -1; } if (ao->i_hog_pid != -1 && ao->i_hog_pid != getpid()) { ao_msg(MSGT_AO, MSGL_WARN, "Selected audio device is exclusively in use by another program.\n" ); goto err_out; } ao->stream_format = inDesc; return OpenSPDIF(); } /* original analog output code */ desc.componentType = kAudioUnitType_Output; desc.componentSubType = (device_id == 0) ? kAudioUnitSubType_DefaultOutput : kAudioUnitSubType_HALOutput; desc.componentManufacturer = kAudioUnitManufacturer_Apple; desc.componentFlags = 0; desc.componentFlagsMask = 0; comp = FindNextComponent(NULL, &desc); //Finds an component that meets the desc spec's if (comp == NULL) { ao_msg(MSGT_AO, MSGL_WARN, "Unable to find Output Unit component\n"); goto err_out; } err = OpenAComponent(comp, &(ao->theOutputUnit)); //gains access to the services provided by the component if (err) { ao_msg(MSGT_AO, MSGL_WARN, "Unable to open Output Unit component: [%4.4s]\n", (char *)&err); goto err_out; } // Initialize AudioUnit err = AudioUnitInitialize(ao->theOutputUnit); if (err) { ao_msg(MSGT_AO, MSGL_WARN, "Unable to initialize Output Unit component: [%4.4s]\n", (char *)&err); goto err_out1; } size = sizeof(AudioStreamBasicDescription); err = AudioUnitSetProperty(ao->theOutputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &inDesc, size); if (err) { ao_msg(MSGT_AO, MSGL_WARN, "Unable to set the input format: [%4.4s]\n", (char *)&err); goto err_out2; } size = sizeof(UInt32); err = AudioUnitGetProperty(ao->theOutputUnit, kAudioDevicePropertyBufferSize, kAudioUnitScope_Input, 0, &maxFrames, &size); if (err) { ao_msg(MSGT_AO,MSGL_WARN, "AudioUnitGetProperty returned [%4.4s] when getting kAudioDevicePropertyBufferSize\n", (char *)&err); goto err_out2; } //Set the Current Device to the Default Output Unit. err = AudioUnitSetProperty(ao->theOutputUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &ao->i_selected_dev, sizeof(ao->i_selected_dev)); ao->chunk_size = maxFrames;//*inDesc.mBytesPerFrame; ao_data.samplerate = inDesc.mSampleRate; ao_data.channels = inDesc.mChannelsPerFrame; ao_data.bps = ao_data.samplerate * inDesc.mBytesPerFrame; ao_data.outburst = ao->chunk_size; ao_data.buffersize = ao_data.bps; ao->num_chunks = (ao_data.bps+ao->chunk_size-1)/ao->chunk_size; ao->buffer_len = ao->num_chunks * ao->chunk_size; ao->buffer = av_fifo_alloc(ao->buffer_len); ao_msg(MSGT_AO,MSGL_V, "using %5d chunks of %d bytes (buffer len %d bytes)\n", (int)ao->num_chunks, (int)ao->chunk_size, (int)ao->buffer_len); renderCallback.inputProc = theRenderProc; renderCallback.inputProcRefCon = 0; err = AudioUnitSetProperty(ao->theOutputUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &renderCallback, sizeof(AURenderCallbackStruct)); if (err) { ao_msg(MSGT_AO, MSGL_WARN, "Unable to set the render callback: [%4.4s]\n", (char *)&err); goto err_out2; } reset(); return CONTROL_OK; err_out2: AudioUnitUninitialize(ao->theOutputUnit); err_out1: CloseComponent(ao->theOutputUnit); err_out: av_fifo_free(ao->buffer); free(ao); ao = NULL; return CONTROL_FALSE; }
/***************************************************************************** * Open: open macosx audio output *****************************************************************************/ CoreAudioAUHAL::CoreAudioAUHAL(const CStdString& strName, const char *strCodec, int channels, unsigned int sampleRate, int bitsPerSample, bool passthrough, bool isMusic, int packetSize) : m_bIsInitialized(false) { OSStatus err = noErr; UInt32 i_param_size = 0; /* Allocate structure */ deviceParameters = (CoreAudioDeviceParameters*)calloc(sizeof(CoreAudioDeviceParameters), 1); if (!deviceParameters) return; if (g_audioConfig.HasDigitalOutput() && // disable encoder for legacy SPDIF devices for now channels > 2 && !passthrough && (sampleRate == SPDIF_SAMPLERATE44 || sampleRate == SPDIF_SAMPLERATE48)) { // Enable AC3 passthrough for digital devices int mpeg_remapping = 0; if (strCodec == "AAC" || strCodec == "DTS") mpeg_remapping = 1; // DTS uses MPEG channel mapping if (ac3encoderInit(&deviceParameters->m_ac3encoder, channels, sampleRate, bitsPerSample, mpeg_remapping) == -1) { m_bIsInitialized = false; return; } else { deviceParameters->m_bEncodeAC3 = true; } } else { deviceParameters->m_bEncodeAC3 = false; } deviceParameters->b_digital = (passthrough || deviceParameters->m_bEncodeAC3) && g_audioConfig.HasDigitalOutput(); deviceParameters->i_hog_pid = -1; deviceParameters->i_stream_index = -1; CLog::Log(LOGNOTICE, "Asked to create device: [%s]", strName.c_str()); CLog::Log(LOGNOTICE, "Device should be digital: [%d]\n", deviceParameters->b_digital); CLog::Log(LOGNOTICE, "CoreAudio S/PDIF mode: [%d]\n", g_audioConfig.UseDigitalOutput()); CLog::Log(LOGNOTICE, "Music mode: [%d]\n", isMusic); CLog::Log(LOGNOTICE, "Channels: [%d]\n", channels); CLog::Log(LOGNOTICE, "Sample Rate: [%d]\n", sampleRate); CLog::Log(LOGNOTICE, "BitsPerSample: [%d]\n", bitsPerSample); CLog::Log(LOGNOTICE, "PacketSize: [%d]\n", packetSize); m_dwPacketSize = packetSize; m_bIsMusic = isMusic; // Build a list of devices. deviceArray = PlexAudioDevices::FindAll(); i_param_size = sizeof(deviceParameters->i_hog_pid); err = AudioDeviceGetProperty( deviceArray->getSelectedDevice()->getDeviceID(), 0, FALSE, kAudioDevicePropertyHogMode, &i_param_size, &deviceParameters->i_hog_pid ); if( err != noErr ) { /* This is not a fatal error. Some drivers simply don't support this property */ CLog::Log(LOGINFO, "could not check whether device is hogged: %4.4s", (char *)&err ); deviceParameters->i_hog_pid = -1; } if( deviceParameters->i_hog_pid != -1 && deviceParameters->i_hog_pid != getpid() ) { CLog::Log(LOGERROR, "Selected audio device is exclusively in use by another program."); return; } deviceParameters->device_id = deviceArray->getSelectedDevice()->getDeviceID(); /* Check for Digital mode or Analog output mode */ if (deviceParameters->b_digital) { if (OpenSPDIF(deviceParameters, strName, channels, sampleRate, bitsPerSample, packetSize)) { m_dwPacketSize = AC3_SPDIF_FRAME_SIZE; m_bIsInitialized = true; return; } } else if (g_audioConfig.ForcedDigital() && (deviceParameters->m_bEncodeAC3 || passthrough)) { if (OpenPCM(deviceParameters, strName, SPDIF_CHANNELS, sampleRate, SPDIF_SAMPLESIZE, packetSize)) { m_bIsInitialized = true; return; } } else { if (OpenPCM(deviceParameters, strName, channels, sampleRate, bitsPerSample, packetSize)) { m_bIsInitialized = true; return; } } error: /* If we reach this, this aout has failed */ //var_Destroy( p_aout, "audio-device" ); free(deviceParameters); m_bIsInitialized = false; //return VLC_EGENERIC; return; }