Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
/*****************************************************************************
 * 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;
}