Пример #1
0
// ----------------------------------------------------------------------------
void AudioCoreDriver::deinitialize()
// ----------------------------------------------------------------------------
{
	if (!mIsInitialized)
		return;
	
	stopPlayback();
	
	AudioDeviceDestroyIOProcID(mDeviceID, mEmulationPlaybackProcID);
	AudioDeviceDestroyIOProcID(mDeviceID, mPreRenderedBufferPlaybackProcID);
#if USE_NEW_API
    OSStatus err;
    AudioObjectPropertyAddress prop5 = {
        kAudioDevicePropertyStreamFormat,
        kAudioDevicePropertyScopeOutput,
        kAudioObjectPropertyElementMaster
    };
    err = AudioObjectRemovePropertyListener(mDeviceID, &prop5, streamFormatChanged, (void*)this);
    if (err != kAudioHardwareNoError)
            printf("AudioObjectRemovePropertyListener(streamFormatChanged) failed\n");

    AudioObjectPropertyAddress prop6 = {
        kAudioDeviceProcessorOverload,
        kAudioDevicePropertyScopeOutput,
        kAudioObjectPropertyElementMaster
    };
    err = AudioObjectRemovePropertyListener(mDeviceID, &prop6, overloadDetected, (void*)this);
    if (err != kAudioHardwareNoError)
            printf("AudioObjectRemovePropertyListener(overloadDetected) failed\n");

    AudioObjectPropertyAddress prop7 = {
        kAudioHardwarePropertyDefaultOutputDevice,
        kAudioDevicePropertyScopeOutput,
        kAudioObjectPropertyElementMaster
    };
    err = AudioObjectRemovePropertyListener(mDeviceID, &prop7, deviceChanged, (void*)this);
    if (err != kAudioHardwareNoError)
            printf("AudioObjectRemovePropertyListener(deviceChanged) failed\n");
#else
	AudioDeviceRemovePropertyListener(mDeviceID, 0, false, kAudioDevicePropertyStreamFormat, streamFormatChanged);
	AudioDeviceRemovePropertyListener(mDeviceID, 0, false, kAudioDeviceProcessorOverload, overloadDetected);
	AudioHardwareRemovePropertyListener(kAudioHardwarePropertyDefaultOutputDevice, deviceChanged);
#endif

	delete[] mSampleBuffer1;
	mSampleBuffer1 = NULL;
	delete[] mSampleBuffer2;
	mSampleBuffer2 = NULL;
    mSampleBuffer = NULL;
    mRetSampleBuffer = NULL;
    delete[] mSpectrumBuffer;
	mSpectrumBuffer = NULL;
	mIsInitialized = false;
}
Пример #2
0
/** free all memory allocated by a driver instance
*/
static void coreaudio_driver_delete(coreaudio_driver_t * driver)
{
 	AudioDeviceRemovePropertyListener(driver->device_id, 0, true, kAudioDeviceProcessorOverload, notification);
    free(driver->input_list);
 	AudioUnitUninitialize(driver->au_hal);
	CloseComponent(driver->au_hal);
    free(driver);
}
Пример #3
0
void	CoreAudioDevice::RemovePropertyListener(UInt32 inChannel, CoreAudioDeviceSection inSection, AudioHardwarePropertyID inPropertyID, AudioDevicePropertyListenerProc inListenerProc)
{
    if (AudioDeviceRemovePropertyListener(deviceID, inChannel, inSection, inPropertyID, inListenerProc) !=0)
    {
        //fprintf(stderr,"Error while Removing device notifications listener. Exiting.");
        //exit(0);
    }
}
Пример #4
0
static int
ca_free (void) {
    if (device_id) {
        AudioDeviceStop(device_id, ca_buffer_callback);
        AudioDeviceRemovePropertyListener(device_id, 0, 0, kAudioDevicePropertyStreamFormat, ca_fmtchanged);
        AudioDeviceRemoveIOProc(device_id, ca_buffer_callback);
    }
    return 0;
}
Пример #5
0
void CCoreAudioSoundManager::Stop()
{
  if (!m_OutputUnit.IsRunning())
    return;
  
  m_OutputUnit.Stop();
  AudioDeviceRemovePropertyListener(m_OutputDevice.GetId(), 0, false, kAudioDevicePropertyHogMode, PropertyChangeCallback); // No longer need to know if the device is hogged
  // TODO: Clean up leftover event(s)
  CLog::Log(LOGDEBUG, "CCoreAudioSoundManager::Stop: SoundManager has been stopped.");
}
Пример #6
0
/** create a new driver instance
*/
static jack_driver_t *coreaudio_driver_new(char* name,
										   jack_client_t* client,
										   jack_nframes_t nframes,
										   jack_nframes_t samplerate,
										   int capturing,
										   int playing,
										   int inchannels,
										   int outchannels,
										   char* capture_driver_uid,
										   char* playback_driver_uid,
										   jack_nframes_t capture_latency, 
										   jack_nframes_t playback_latency)
{
    coreaudio_driver_t *driver;
	OSStatus err = noErr;
	ComponentResult err1;
    UInt32 outSize;
	UInt32 enableIO;
	AudioStreamBasicDescription srcFormat, dstFormat;
	Float64 sampleRate;
	int in_nChannels = 0;
	int out_nChannels = 0;
	int i;
	
    driver = (coreaudio_driver_t *) calloc(1, sizeof(coreaudio_driver_t));
    jack_driver_init((jack_driver_t *) driver);

    if (!jack_power_of_two(nframes)) {
		jack_error("CA: -p must be a power of two.");
		goto error;
    }

	driver->state = 0;
    driver->frames_per_cycle = nframes;
    driver->frame_rate = samplerate;
    driver->capturing = capturing;
    driver->playing = playing;
	driver->xrun_detected = 0;
	driver->null_cycle = 0;

    driver->attach = (JackDriverAttachFunction) coreaudio_driver_attach;
    driver->detach = (JackDriverDetachFunction) coreaudio_driver_detach;
    driver->read = (JackDriverReadFunction) coreaudio_driver_read;
    driver->write = (JackDriverReadFunction) coreaudio_driver_write;
    driver->null_cycle =
	(JackDriverNullCycleFunction) coreaudio_driver_null_cycle;
    driver->bufsize = (JackDriverBufSizeFunction) coreaudio_driver_bufsize;
    driver->start = (JackDriverStartFunction) coreaudio_driver_audio_start;
    driver->stop = (JackDriverStopFunction) coreaudio_driver_audio_stop;
	driver->capture_frame_latency = capture_latency;
	driver->playback_frame_latency = playback_latency;
	
	// Duplex
    if (strcmp(capture_driver_uid, "") != 0 && strcmp(playback_driver_uid, "") != 0) {
		JCALog("Open duplex \n");
        if (get_device_id_from_uid(playback_driver_uid, &driver->device_id) != noErr) {
            if (get_default_device(&driver->device_id) != noErr) {
				jack_error("Cannot open default device");
				goto error;
			}
		}
		if (get_device_name_from_id(driver->device_id, driver->capture_driver_name) != noErr || get_device_name_from_id(driver->device_id, driver->playback_driver_name) != noErr) {
			jack_error("Cannot get device name from device ID");
			goto error;
		}
		
	// Capture only
	} else if (strcmp(capture_driver_uid, "") != 0) {
		JCALog("Open capture only \n");
		if (get_device_id_from_uid(capture_driver_uid, &driver->device_id) != noErr) {
            if (get_default_input_device(&driver->device_id) != noErr) {
				jack_error("Cannot open default device");
                goto error;
			}
		}
		if (get_device_name_from_id(driver->device_id, driver->capture_driver_name) != noErr) {
			jack_error("Cannot get device name from device ID");
			goto error;
		}
		
  	// Playback only
	} else if (playback_driver_uid != NULL) {
		JCALog("Open playback only \n");
		if (get_device_id_from_uid(playback_driver_uid, &driver->device_id) != noErr) {
            if (get_default_output_device(&driver->device_id) != noErr) {
				jack_error("Cannot open default device");
                goto error;
			}
        }
		if (get_device_name_from_id(driver->device_id, driver->playback_driver_name) != noErr) {
			jack_error("Cannot get device name from device ID");
			goto error;
		}
		
	// Use default driver in duplex mode
	} else {
		JCALog("Open default driver \n");
		if (get_default_device(&driver->device_id) != noErr) {
			jack_error("Cannot open default device");
			goto error;
		}
		if (get_device_name_from_id(driver->device_id, driver->capture_driver_name) != noErr || get_device_name_from_id(driver->device_id, driver->playback_driver_name) != noErr) {
			jack_error("Cannot get device name from device ID");
			goto error;
		}
	}
	
	driver->client = client;
    driver->period_usecs =
		(((float) driver->frames_per_cycle) / driver->frame_rate) *
		1000000.0f;
	
	if (capturing) {
		err = get_total_channels(driver->device_id, &in_nChannels, true);
		if (err != noErr) { 
			jack_error("Cannot get input channel number");
			printError(err);
			goto error;
		} 
	}
	
	if (playing) {
		err = get_total_channels(driver->device_id, &out_nChannels, false);
		if (err != noErr) { 
			jack_error("Cannot get output channel number");
			printError(err);
			goto error;
		} 
	}
	
	if (inchannels > in_nChannels) {
        jack_error("This device hasn't required input channels inchannels = %ld in_nChannels = %ld", inchannels, in_nChannels);
		goto error;
    }
	
	if (outchannels > out_nChannels) {
        jack_error("This device hasn't required output channels outchannels = %ld out_nChannels = %ld", outchannels, out_nChannels);
		goto error;
    }

	if (inchannels == 0) {
		JCALog("Setup max in channels = %ld\n", in_nChannels);
		inchannels = in_nChannels; 
	}
		
	if (outchannels == 0) {
		JCALog("Setup max out channels = %ld\n", out_nChannels);
		outchannels = out_nChannels; 
	}

    // Setting buffer size
    outSize = sizeof(UInt32);
    err = AudioDeviceSetProperty(driver->device_id, NULL, 0, false, kAudioDevicePropertyBufferFrameSize, outSize, &nframes);
    if (err != noErr) {
        jack_error("Cannot set buffer size %ld", nframes);
        printError(err);
		goto error;
    }

	// Set sample rate
	outSize =  sizeof(Float64);
	err = AudioDeviceGetProperty(driver->device_id, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate);
	if (err != noErr) {
		jack_error("Cannot get current sample rate");
		printError(err);
		goto error;
	}

	if (samplerate != (jack_nframes_t)sampleRate) {
		sampleRate = (Float64)samplerate;
		
		// To get SR change notification
		err = AudioDeviceAddPropertyListener(driver->device_id, 0, true, kAudioDevicePropertyNominalSampleRate, sr_notification, driver);
		if (err != noErr) {
			jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate");
			printError(err);
			return -1;
		}
		err = AudioDeviceSetProperty(driver->device_id, NULL, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, outSize, &sampleRate);
		if (err != noErr) {
			jack_error("Cannot set sample rate = %ld", samplerate);
			printError(err);
			return -1;
		}
		
		// Waiting for SR change notification
		int count = 0;
		while (!driver->state && count++ < 100) {
			usleep(100000);
			JCALog("Wait count = %ld\n", count);
		}
		
		// Remove SR change notification
		AudioDeviceRemovePropertyListener(driver->device_id, 0, true, kAudioDevicePropertyNominalSampleRate, sr_notification);
	}

    // AUHAL
    ComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0};
    Component HALOutput = FindNextComponent(NULL, &cd);

    err1 = OpenAComponent(HALOutput, &driver->au_hal);
    if (err1 != noErr) {
		jack_error("Error calling OpenAComponent");
        printError(err1);
        goto error;
	}

    err1 = AudioUnitInitialize(driver->au_hal);
    if (err1 != noErr) {
		jack_error("Cannot initialize AUHAL unit");
		printError(err1);
        goto error;
	}

 	// Start I/O
	enableIO = 1;
	if (capturing && inchannels > 0) {
		JCALog("Setup AUHAL input\n");
        err1 = AudioUnitSetProperty(driver->au_hal, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO));
        if (err1 != noErr) {
            jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input");
            printError(err1);
            goto error;
        }
    }
	
	if (playing && outchannels > 0) {
		JCALog("Setup AUHAL output\n");
		err1 = AudioUnitSetProperty(driver->au_hal, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO));
		if (err1 != noErr) {
			jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Output");
			printError(err1);
			goto error;
		}
	}
	
	// Setup up choosen device, in both input and output cases
	err1 = AudioUnitSetProperty(driver->au_hal, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &driver->device_id, sizeof(AudioDeviceID));
	if (err1 != noErr) {
		jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_CurrentDevice");
		printError(err1);
		goto error;
	}

	// Set buffer size
	if (capturing && inchannels > 0) {
		err1 = AudioUnitSetProperty(driver->au_hal, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, (UInt32*)&nframes, sizeof(UInt32));
		if (err1 != noErr) {
			jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice");
			printError(err1);
			goto error;
		}
	}
	
	if (playing && outchannels > 0) {
		err1 = AudioUnitSetProperty(driver->au_hal, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, (UInt32*)&nframes, sizeof(UInt32));
		if (err1 != noErr) {
			jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice");
			printError(err1);
			goto error;
		}
	}

	// Setup channel map
	if (capturing && inchannels > 0 && inchannels < in_nChannels) {
        SInt32 chanArr[in_nChannels];
        for (i = 0; i < in_nChannels; i++) {
            chanArr[i] = -1;
        }
        for (i = 0; i < inchannels; i++) {
            chanArr[i] = i;
        }
        AudioUnitSetProperty(driver->au_hal, kAudioOutputUnitProperty_ChannelMap , kAudioUnitScope_Input, 1, chanArr, sizeof(SInt32) * in_nChannels);
        if (err1 != noErr) {
            jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 1");
            printError(err1);
        }
    }

    if (playing && outchannels > 0 && outchannels < out_nChannels) {
        SInt32 chanArr[out_nChannels];
        for (i = 0;	i < out_nChannels; i++) {
            chanArr[i] = -1;
        }
        for (i = 0; i < outchannels; i++) {
            chanArr[i] = i;
        }
        err1 = AudioUnitSetProperty(driver->au_hal, kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Output, 0, chanArr, sizeof(SInt32) * out_nChannels);
        if (err1 != noErr) {
            jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 0");
            printError(err1);
        }
    }

	// Setup stream converters
  	srcFormat.mSampleRate = samplerate;
	srcFormat.mFormatID = kAudioFormatLinearPCM;
	srcFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
	srcFormat.mBytesPerPacket = sizeof(float);
	srcFormat.mFramesPerPacket = 1;
	srcFormat.mBytesPerFrame = sizeof(float);
	srcFormat.mChannelsPerFrame = outchannels;
	srcFormat.mBitsPerChannel = 32;

	err1 = AudioUnitSetProperty(driver->au_hal, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &srcFormat, sizeof(AudioStreamBasicDescription));
	if (err1 != noErr) {
		jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input");
		printError(err1);
	}

	dstFormat.mSampleRate = samplerate;
	dstFormat.mFormatID = kAudioFormatLinearPCM;
	dstFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
	dstFormat.mBytesPerPacket = sizeof(float);
	dstFormat.mFramesPerPacket = 1;
	dstFormat.mBytesPerFrame = sizeof(float);
	dstFormat.mChannelsPerFrame = inchannels;
	dstFormat.mBitsPerChannel = 32;

	err1 = AudioUnitSetProperty(driver->au_hal, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &dstFormat, sizeof(AudioStreamBasicDescription));
	if (err1 != noErr) {
		jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output");
		printError(err1);
	}

	// Setup callbacks
    if (inchannels > 0 && outchannels == 0) {
        AURenderCallbackStruct output;
        output.inputProc = render_input;
        output.inputProcRefCon = driver;
    	err1 = AudioUnitSetProperty(driver->au_hal, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &output, sizeof(output));
        if (err1 != noErr) {
            jack_error("Error calling  AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 1");
            printError(err1);
            goto error;
        }
    } else {
        AURenderCallbackStruct output;
        output.inputProc = render;
        output.inputProcRefCon = driver;
        err1 = AudioUnitSetProperty(driver->au_hal, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &output, sizeof(output));
        if (err1 != noErr) {
            jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 0");
            printError(err1);
            goto error;
        }
    }

	if (capturing && inchannels > 0) {
		driver->input_list = (AudioBufferList*)malloc(sizeof(UInt32) + inchannels * sizeof(AudioBuffer));
		if (driver->input_list == 0)
			goto error;
		driver->input_list->mNumberBuffers = inchannels;
		
		// Prepare buffers
		for (i = 0; i < driver->capture_nchannels; i++) {
			driver->input_list->mBuffers[i].mNumberChannels = 1;
			driver->input_list->mBuffers[i].mDataByteSize = nframes * sizeof(float);
		}
	}

	err = AudioDeviceAddPropertyListener(driver->device_id, 0, true, kAudioDeviceProcessorOverload, notification, driver);
    if (err != noErr) {
		jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDeviceProcessorOverload");
        goto error;
	}
		
	err = AudioDeviceAddPropertyListener(driver->device_id, 0, true, kAudioDevicePropertyNominalSampleRate, notification, driver);
    if (err != noErr) {
        jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate");
        goto error;
    }
 
	driver->playback_nchannels = outchannels;
    driver->capture_nchannels = inchannels;
	return ((jack_driver_t *) driver);

  error:
	AudioUnitUninitialize(driver->au_hal);
	CloseComponent(driver->au_hal);
    jack_error("Cannot open the coreaudio driver");
    free(driver);
    return NULL;
}
/* sets the value of the given property and waits for the change to 
   be acknowledged, and returns the final value, which is not guaranteed
   by this function to be the same as the desired value. Obviously, this
   function can only be used for data whose input and output are the
   same size and format, and their size and format are known in advance.*/
PaError AudioDeviceSetPropertyNowAndWaitForChange(
    AudioDeviceID inDevice,
    UInt32 inChannel, 
    Boolean isInput, 
    AudioDevicePropertyID inPropertyID,
    UInt32 inPropertyDataSize, 
    const void *inPropertyData,
    void *outPropertyData )
{
   OSStatus macErr;
   int unixErr;
   MutexAndBool mab;
   UInt32 outPropertyDataSize = inPropertyDataSize;

   /* First, see if it already has that value. If so, return. */
   macErr = AudioDeviceGetProperty( inDevice, inChannel,
                                 isInput, inPropertyID, 
                                 &outPropertyDataSize, outPropertyData );
   if( macErr )
      goto failMac2;
   if( inPropertyDataSize!=outPropertyDataSize )
      return paInternalError;
   if( 0==memcmp( outPropertyData, inPropertyData, outPropertyDataSize ) )
      return paNoError;

   /* setup and lock mutex */
   mab.once = FALSE;
   unixErr = pthread_mutex_init( &mab.mutex, NULL );
   if( unixErr )
      goto failUnix2;
   unixErr = pthread_mutex_lock( &mab.mutex );
   if( unixErr )
      goto failUnix;

   /* add property listener */
   macErr = AudioDeviceAddPropertyListener( inDevice, inChannel, isInput,
                                   inPropertyID, propertyProc,
                                   &mab ); 
   if( macErr )
      goto failMac;
   /* set property */
   macErr  = AudioDeviceSetProperty( inDevice, NULL, inChannel,
                                 isInput, inPropertyID,
                                 inPropertyDataSize, inPropertyData );
   if( macErr ) {
      /* we couldn't set the property, so we'll just unlock the mutex
         and move on. */
      pthread_mutex_unlock( &mab.mutex );
   }

   /* wait for property to change */                      
   unixErr = pthread_mutex_lock( &mab.mutex );
   if( unixErr )
      goto failUnix;

   /* now read the property back out */
   macErr = AudioDeviceGetProperty( inDevice, inChannel,
                                 isInput, inPropertyID, 
                                 &outPropertyDataSize, outPropertyData );
   if( macErr )
      goto failMac;
   /* cleanup */
   AudioDeviceRemovePropertyListener( inDevice, inChannel, isInput,
                                      inPropertyID, propertyProc );
   unixErr = pthread_mutex_unlock( &mab.mutex );
   if( unixErr )
      goto failUnix2;
   unixErr = pthread_mutex_destroy( &mab.mutex );
   if( unixErr )
      goto failUnix2;

   return paNoError;

 failUnix:
   pthread_mutex_destroy( &mab.mutex );
   AudioDeviceRemovePropertyListener( inDevice, inChannel, isInput,
                                      inPropertyID, propertyProc );

 failUnix2:
   DBUG( ("Error #%d while setting a device property: %s\n", unixErr, strerror( unixErr ) ) );
   return paUnanticipatedHostError;

 failMac:
   pthread_mutex_destroy( &mab.mutex );
   AudioDeviceRemovePropertyListener( inDevice, inChannel, isInput,
                                      inPropertyID, propertyProc );
 failMac2:
   return ERR( macErr );
}