initial coreaudio patch

This commit is contained in:
rafael@riseup.net 2009-11-11 16:02:38 +00:00
parent 6014ba09bd
commit 63c68d3659
7 changed files with 1112 additions and 2 deletions

View File

@ -301,6 +301,20 @@ else
fi
dnl-----------------------------------------------------------------------------
dnl link CoreAudio framework
dnl-----------------------------------------------------------------------------
AC_SUBST(COREAUDIO_LDFLAGS)
# Look for Core flag
AC_ARG_WITH(core, [ --with-core = choose CoreAudio API support (mac only)], [
AC_MSG_RESULT(using CoreAudio)
AC_CHECK_HEADER(CoreAudio/CoreAudio.h, [], [AC_MSG_ERROR(CoreAudio header files not found!)] )
COREAUDIO_LDFLAGS="-framework CoreAudio -framework CoreFoundation"
AC_DEFINE( HAVE_COREAUDIO_LIB, 1, [build with CoreAudio support] ) ], )
dnl-----------------------------------------------------------------------------
dnl check for MSG_NOSIGNAL for the send() function in libsocket
dnl-----------------------------------------------------------------------------

View File

@ -118,6 +118,12 @@ AudioSource :: createDspSource( const char * deviceName,
sampleRate,
bitsPerSample,
channel);
#elif defined( SUPPORT_COREAUDIO_DSP )
Reporter::reportEvent( 1, "Using CoreAudio as input device.");
return new CoreAudioDspSource( deviceName,
sampleRate,
bitsPerSample,
channel);
#else
throw Exception( __FILE__, __LINE__,
"trying to open ALSA DSP device without "

View File

@ -71,6 +71,11 @@
#define SUPPORT_JACK_DSP 1
#endif
#if defined( HAVE_COREAUDIO_LIB )
// we have CoreAudio framework
#define SUPPORT_COREAUDIO_DSP 1
#endif
#if defined ( HAVE_TERMIOS_H )
#define SUPPORT_SERIAL_ULAW 1
#endif
@ -78,6 +83,7 @@
#if !defined( SUPPORT_ALSA_DSP ) \
&& !defined( SUPPORT_OSS_DSP ) \
&& !defined( SUPPORT_JACK_DSP ) \
&& !defined( SUPPORT_COREAUDIO_DSP ) \
&& !defined( SUPPORT_SOLARIS_DSP ) \
&& !defined( SUPPORT_SERIAL_ULAW)
// there was no DSP audio system found
@ -301,6 +307,10 @@ class AudioSource : public Source, public virtual Reporter
#include "JackDspSource.h"
#endif
#if defined( SUPPORT_COREAUDIO_DSP )
#include "CoreAudioDspSource.h"
#endif
#if defined ( SUPPORT_SERIAL_ULAW )
#include "SerialUlaw.h"
#endif

View File

@ -0,0 +1,807 @@
#include "AudioSource.h"
#ifdef SUPPORT_COREAUDIO_DSP
// only compile this code if there is support for it
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#else
#error need unistd.h
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#else
#error need string.h
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#else
#error need sys/types.h
#endif
#ifdef HAVE_MATH_H
#include <math.h>
#else
#error need math.h
#endif
#include <CoreFoundation/CoreFoundation.h>
#include <CoreAudio/AudioHardware.h>
#include "Util.h"
#include "Exception.h"
#include "CoreAudioDspSource.h"
/* =================================================== local data structures */
/* ================================================ local constants & macros */
/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id: CoreAudioDspSource.cpp $";
/* =============================================== local function prototypes */
static unsigned int get_device_count(void);
static const char* get_error_name( OSStatus code );
/* ============================================================= module code */
/*------------------------------------------------------------------------------
* Tell if source id big endian
*----------------------------------------------------------------------------*/
bool
CoreAudioDspSource :: isBigEndian ( void ) const throw ()
{
//According to AudioHardware.h, the stream data will
// always be presented in native-endian format
CFByteOrder order = CFByteOrderGetCurrent();
return (CFByteOrderBigEndian == order);
}
/*------------------------------------------------------------------------------
* Initialize the object
*----------------------------------------------------------------------------*/
void
CoreAudioDspSource :: init ( const char* name ) throw ( Exception )
{
// Set defaults
rb[0] = NULL; // Left Ring Buffer
rb[1] = NULL; // Right Ring Buffer
tmp_buffer = NULL; // Buffer big enough for one 'read' of audio
cnv_buffer = NULL; // For converting.
is_running = false; //
is_opened = false;
// Check the sample size
if (
#if 0
// don't work.
getBitsPerSample() != 8 &&
#endif
getBitsPerSample() != 16) {
throw Exception( __FILE__, __LINE__,
"CoreAudioDspSource doesn't support non 16-bit samples");
}
Reporter::reportEvent( 10, "CoreAudioDspSource :: init():bitsPerSample ", getBitsPerSample());
unsigned int dev_count = get_device_count();
if (dev_count == 0) {
throw Exception( __FILE__, __LINE__, "no input device found");
}
AudioDeviceID id;
UInt32 data_size = sizeof(AudioDeviceID);
OSStatus result = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice,
&data_size, &id);
if (result != noErr) {
throw Exception( __FILE__, __LINE__,
"faild to get DefaultInputDevice:", get_error_name(result));
}
// Use default device ?
if ( Util::strEq( name, "default", 7) ) {
device_id = id;
char dev_name[256];
data_size = sizeof(dev_name);
result = AudioDeviceGetProperty(device_id, 0, true,
kAudioDevicePropertyDeviceName, &data_size, &dev_name[0]);
if (result != noErr) {
throw Exception( __FILE__, __LINE__,
"faild to get device name:", get_error_name(result));
}
dev_name[sizeof(dev_name) - 1] = '\0';
Reporter::reportEvent( 1, "CoreAudioDspSource :: init():name ", &dev_name[0]);
return;
}
data_size *= dev_count;
AudioDeviceID *device_list = (AudioDeviceID *)malloc(dev_count * sizeof(AudioDeviceID));
if (!device_list) {
throw Exception( __FILE__, __LINE__, "faild to allocate memory for device_list");
}
result = AudioHardwareGetProperty(kAudioHardwarePropertyDevices,
&data_size, device_list);
if (result != noErr) {
free(device_list);
device_list = NULL;
throw Exception( __FILE__, __LINE__, "faild to get Devices:", get_error_name(result));
}
bool dev_found = false;
for (unsigned int i = 0; i < dev_count; ++i) {
id = device_list[i];
char dev_name[256];
data_size = sizeof(dev_name);
result = AudioDeviceGetProperty(id, 0, false,
kAudioDevicePropertyDeviceName,
&data_size, &dev_name[0]);
if (result != noErr) {
free(device_list);
device_list = NULL;
throw Exception( __FILE__, __LINE__, "faild to get Device name:", get_error_name(result));
}
if (strcmp(&dev_name[0], name) == 0) {
device_id = id;
dev_found = true;
char dev_name[256];
data_size = sizeof(dev_name);
result = AudioDeviceGetProperty(device_id, 0, true,
kAudioDevicePropertyDeviceName, &data_size, &dev_name[0]);
if (result != noErr) {
throw Exception( __FILE__, __LINE__,
"faild to get device name:", get_error_name(result));
}
dev_name[sizeof(dev_name) - 1] = '\0';
Reporter::reportEvent( 1, "CoreAudioDspSource :: init():name ", &dev_name[0]);
break;
}
}
free(device_list);
device_list = NULL;
if (!dev_found) {
throw Exception( __FILE__, __LINE__, "device is not found.");
}
}
/*------------------------------------------------------------------------------
* De-initialize the object
*----------------------------------------------------------------------------*/
void
CoreAudioDspSource :: strip ( void ) throw ( Exception )
{
if ( isOpen() ) {
close();
}
// Free the temporary buffer
if (tmp_buffer) {
free(tmp_buffer);
tmp_buffer = NULL;
}
if (cnv_buffer) {
free(cnv_buffer);
cnv_buffer = NULL;
}
}
/*------------------------------------------------------------------------------
* Open the audio source
*----------------------------------------------------------------------------*/
bool
CoreAudioDspSource :: open ( void ) throw ( Exception )
{
size_t rb_size = 0;
unsigned int c = 0;;
if ( isOpen() ) {
return false;
}
// Create a ring buffer for each channel
rb_size = 8 * getSampleRate() * sizeof(Float32);
for (c = 0; c < getChannel(); c++) {
rb[c] = jack_ringbuffer_create(rb_size);
if (!rb[c]) {
throw Exception( __FILE__, __LINE__,
"Failed to create ringbuffer for channel ", c);
}
}
OSStatus result = noErr;
UInt32 data_size = 0;;
// Set BufferFrameSize
UInt32 buffer_size = 512;
data_size = sizeof(UInt32);
result = AudioDeviceSetProperty(device_id, NULL, 0, true,
kAudioDevicePropertyBufferFrameSize, data_size, &buffer_size);
if (result != noErr) {
throw Exception( __FILE__, __LINE__,
"Can't set buffer frame size:", get_error_name(result));
}
data_size = sizeof(UInt32);
result = AudioDeviceGetProperty(device_id, 0, true,
kAudioDevicePropertyBufferFrameSize, &data_size, &buffer_size);
if (result != noErr) {
throw Exception( __FILE__, __LINE__,
"Can't get buffer frame size:", get_error_name(result));
}
Reporter::reportEvent( 10, "CoreAudioDspSource :: open():buffer frame size: ", buffer_size);
// Get the stream configration.
result = AudioDeviceGetPropertyInfo(device_id, 0, true,
kAudioDevicePropertyStreamConfiguration,
&data_size, NULL);
if (data_size == 0) {
throw Exception( __FILE__, __LINE__,
"Can't get stream configuration ", "data_size is zero");
}
if (result != noErr) {
throw Exception( __FILE__, __LINE__,
"Can't get stream configuration ", get_error_name(result));
}
// Allocate buffer
AudioBufferList *buffer_list = (AudioBufferList *)malloc(data_size);
if (!buffer_list) {
throw Exception( __FILE__, __LINE__, "Can't allocate buffer ", get_error_name(result));
}
result = AudioDeviceGetProperty(device_id, 0, true,
kAudioDevicePropertyStreamConfiguration,
&data_size, buffer_list);
if (result != noErr) {
free(buffer_list);
buffer_list = NULL;
throw Exception( __FILE__, __LINE__,
"Can't get stream configuration ", get_error_name(result));
}
UInt32 dev_channels = 0;
for (UInt32 i = 0; i < buffer_list->mNumberBuffers; i++) {
dev_channels += buffer_list->mBuffers[i].mNumberChannels;
}
if (getChannel() > dev_channels) {
free(buffer_list);
buffer_list = NULL;
throw Exception( __FILE__, __LINE__,
"Invalid number of channels", getChannel());
}
free(buffer_list);
buffer_list = NULL;
// set stream format.
Float64 sample_rate = getSampleRate();
data_size = sizeof(sample_rate);
result = AudioDeviceSetProperty(device_id, 0, true, 0,
kAudioDevicePropertyNominalSampleRate, data_size, &sample_rate);
if (result != noErr) {
throw Exception( __FILE__, __LINE__, "Can't set stream format:", get_error_name(result));
}
AudioStreamBasicDescription description;
data_size = sizeof(description);
result = AudioDeviceGetProperty(device_id, 0, true,
kAudioDevicePropertyStreamFormat, &data_size, &description);
if (result != noErr) {
throw Exception( __FILE__, __LINE__, "Can't get stream format:", get_error_name(result));
}
#if 0
fprintf(stderr, "stream format:sr=%f\nfid='%c%c%c%c'\nflags=0x%x\ncpf=%u\nbpf=%u\nbpp=%u\n",
description.mSampleRate,
(description.mFormatID >> 24) & 0x00ff, (description.mFormatID >> 16) & 0x00ff,
(description.mFormatID >> 8) & 0x00ff, description.mFormatID & 0x00ff,
description.mFormatFlags,
description.mChannelsPerFrame,
description.mBytesPerFrame,
description.mBytesPerPacket);
#endif
if (description.mChannelsPerFrame != 1 && description.mChannelsPerFrame != 2) {
throw Exception( __FILE__, __LINE__, "not supported device channels ", description.mChannelsPerFrame);
}
stream_description = description;
is_opened = true;
return true;
}
/*------------------------------------------------------------------------------
* Check wether read() would return anything
*----------------------------------------------------------------------------*/
bool
CoreAudioDspSource :: canRead ( unsigned int sec,
unsigned int usec ) throw ( Exception )
{
const unsigned int max_wait_time = sec * 1000000;
const unsigned int wait_increment = 10000;
unsigned int cur_wait = 0;
if ( !isOpen() ) {
return false;
}
if (!is_running) {
startDevice();
}
while (max_wait_time > cur_wait) {
bool canRead = true;
for (unsigned int c = 0 ; c < getChannel() ; c++) {
if (jack_ringbuffer_read_space(rb[c]) <= 0) {
canRead = false;
}
}
if (canRead) {
return true;
}
cur_wait += wait_increment;
usleep ( wait_increment );
}
usleep( usec );
for (unsigned int c = 0 ; c < getChannel() ; c++) {
if (jack_ringbuffer_read_space(rb[c]) <= 0) {
return false;
}
}
return true;
}
/*------------------------------------------------------------------------------
* Read from the audio source
*----------------------------------------------------------------------------*/
unsigned int
CoreAudioDspSource :: read ( void * buf,
unsigned int len ) throw ( Exception )
{
unsigned int samples = len / (getBitsPerSample() >> 3) / getChannel();
unsigned int samples_read[2] = {0,0};
unsigned int c, n;
if ( !isOpen() ) {
return 0;
}
if (!is_running) {
startDevice();
}
// Ensure the temporary buffer is big enough
tmp_buffer = (char *)realloc(tmp_buffer, samples * sizeof(Float32));
if (!tmp_buffer) {
throw Exception( __FILE__, __LINE__, "realloc on tmp_buffer failed");
}
// We must be sure to fetch as many data on both channels
int minBytesAvailable = samples * sizeof(Float32);
for (c = 0; c < getChannel(); c++) {
int readable = jack_ringbuffer_read_space(rb[c]);
if (readable < minBytesAvailable) {
minBytesAvailable = readable;
}
}
for (c = 0; c < getChannel(); c++) {
// Copy frames from ring buffer to temporary buffer
// and then convert samples to output buffer
int bytes_read = jack_ringbuffer_read(rb[c],
(char*)tmp_buffer,
minBytesAvailable);
samples_read[c] = bytes_read / sizeof(Float32);
// Convert samples from float to char/short and put in output buffer
if (getBitsPerSample() == 8) {
char *output8 = (char*)buf;
Float32 *in = (Float32 *)tmp_buffer;
for (n = 0; n < samples_read[c]; n++) {
int tmp = lrintf(in[n] * 128.0f);
if (tmp > CHAR_MAX) {
output8[n * getChannel() + c] = CHAR_MAX;
} else if (tmp < CHAR_MIN) {
output8[n * getChannel() + c] = CHAR_MIN;
} else {
output8[n * getChannel() + c] = (char)tmp;
}
}
} else { // 16
short *output16 = (short*)buf;
Float32 *in = (Float32 *)tmp_buffer;
for (n = 0; n < samples_read[c]; n++) {
int tmp = lrintf(in[n] * 32768.0f);
if (tmp > SHRT_MAX) {
output16[n * getChannel() + c] = SHRT_MAX;
} else if (tmp < SHRT_MIN) {
output16[n * getChannel() + c] = SHRT_MIN;
} else {
output16[n * getChannel() + c] = (short)tmp;
}
}
}
}
// Didn't get as many samples as we wanted ?
if (getChannel() == 2 && samples_read[0] != samples_read[1]) {
Reporter::reportEvent( 2,
"Warning: Read a different number of samples "
"for left and right channels");
}
// Return the number of bytes put in the output buffer
return samples_read[0] * (getBitsPerSample() >> 3) * getChannel();
}
/*------------------------------------------------------------------------------
* Close the audio source
*----------------------------------------------------------------------------*/
void
CoreAudioDspSource :: close ( void ) throw ( Exception )
{
unsigned int i;
if ( !isOpen() ) {
return;
}
if (is_running) {
stopDevice();
}
for (i = 0; i < getChannel(); i++) {
if (rb[i]) {
jack_ringbuffer_free(rb[i]);
rb[i] = NULL;
}
}
is_opened = false;
}
/*------------------------------------------------------------------------------
* Callback called by CoreAudio when audio is available
*
* Don't do anything too expensive here
* - just shove audio samples in ring buffer
*----------------------------------------------------------------------------*/
OSStatus
CoreAudioDspSource :: callback_handler( AudioDeviceID inDevice,
const AudioTimeStamp *inNow,
const AudioBufferList *inInputData,
const AudioTimeStamp *inInputTime,
AudioBufferList *outOutputData,
const AudioTimeStamp *inOutputTime,
void *infoPointer )
{
CoreAudioDspSource *self = (CoreAudioDspSource *)infoPointer;
bool err = false;
if (self->stream_description.mFormatFlags & kAudioFormatFlagIsNonInterleaved) {
#if 1
Reporter::reportEvent( 1, "not supported.");
err = true;
#else
unsigned int c;
//XXX not tested.
/* copy data to ringbuffer; one per channel */
if ((self->getChannel() == 2 && self->stream_description.mChannelsPerFrame == 2)
|| (self->getChannel() == 1 && self->stream_description.mChannelsPerFrame == 1)) {
for (c = 0; c < self->getChannel(); c++) {
char *buf = (char*)inInputData->mBuffers[c].mData;
size_t to_write = inInputData->mBuffers[c].mDataByteSize;
size_t len = jack_ringbuffer_write(self->rb[c], buf, to_write);
if (len < to_write) {
Reporter::reportEvent( 1, "failed to write to ring buffer");
err = true;
}
}
} else if (self->getChannel() == 1 && self->stream_description.mChannelsPerFrame == 2) {
Float32 *dataL = (Float32 *)inInputData->mBuffers[0].mData;
Float32 *dataR = (Float32 *)inInputData->mBuffers[1].mData;
size_t to_write = inInputData->mBuffers[0].mDataByteSize;
size_t sz = to_write / sizeof(Float32);
for (unsigned i = 0; i < sz; i++) {
dataL[i] = (dataL[i] + dataR[i]) / 2.0;
}
size_t len = jack_ringbuffer_write(self->rb[0], (char *)dataL, to_write);
if (len < to_write) {
Reporter::reportEvent( 1, "failed to write to ring buffer");
err = true;
}
} else if (self->getChannel() == 2 && self->stream_description.mChannelsPerFrame == 1) {
for (c = 0; c < self->getChannel(); c++) {
char *buf = (char*)inInputData->mBuffers[0].mData;
size_t to_write = inInputData->mBuffers[0].mDataByteSize;
size_t len = jack_ringbuffer_write(self->rb[c], buf, to_write);
if (len < to_write) {
Reporter::reportEvent( 1, "failed to write to ring buffer");
err = true;
}
}
} else {
Reporter::reportEvent( 1, "not reach here.");
err = true;
}
#endif
} else {
Float32 *data = (Float32 *)inInputData->mBuffers[0].mData;
if (self->getChannel() == 2 && self->stream_description.mChannelsPerFrame == 2) {
// Ensure the temporary buffer is big enough
size_t sz = inInputData->mBuffers[0].mDataByteSize;
self->cnv_buffer = (char *)realloc(self->cnv_buffer, sz);
if (!self->cnv_buffer) {
Reporter::reportEvent( 1, "realloc on cnv_buffer failed");
return kAudioHardwareUnspecifiedError;
}
size_t to_write = sz / 2;
Float32 *dataL = (Float32 *)self->cnv_buffer;
Float32 *dataR = (Float32 *)(self->cnv_buffer + to_write);
sz /= sizeof(Float32);
for (unsigned int i = 0; i < sz; i += 2) {
dataL[i / 2] = data[i];
dataR[i / 2] = data[i + 1];
}
size_t len = jack_ringbuffer_write(self->rb[0], (char *)dataL, to_write);
if (len < to_write) {
Reporter::reportEvent( 1, "failed to write to ring buffer");
err = true;
}
len = jack_ringbuffer_write(self->rb[1], (char *)dataR, to_write);
if (len < to_write) {
Reporter::reportEvent( 1, "failed to write to ring buffer");
err = true;
}
} else if (self->getChannel() == 1 && self->stream_description.mChannelsPerFrame == 2) {
// Ensure the temporary buffer is big enough
size_t sz = inInputData->mBuffers[0].mDataByteSize;
self->cnv_buffer = (char *)realloc(self->cnv_buffer, sz / 2);
if (!self->cnv_buffer) {
Reporter::reportEvent( 1, "realloc on cnv_buffer failed");
return kAudioHardwareUnspecifiedError;
}
size_t to_write = sz / 2;
Float32 *dataM = (Float32 *)self->cnv_buffer;
sz /= sizeof(Float32);
for (unsigned int i = 0; i < sz; i += 2) {
dataM[i / 2] = ((data[i] + data[i + 1]) / 2.0);
}
size_t len = jack_ringbuffer_write(self->rb[0], (char *)dataM, to_write);
if (len < to_write) {
Reporter::reportEvent( 1, "failed to write to ring buffer");
err = true;
}
} else if (self->getChannel() == 2 && self->stream_description.mChannelsPerFrame == 1) {
#if 1
Reporter::reportEvent( 1, "not supported.");
err = true;
#else
//XXX not tested.
// Ensure the temporary buffer is big enough
size_t sz = inInputData->mBuffers[0].mDataByteSize;
self->cnv_buffer = (char *)realloc(self->cnv_buffer, sz * 2);
if (!self->cnv_buffer) {
Reporter::reportEvent( 1, "realloc on cnv_buffer failed");
return kAudioHardwareUnspecifiedError;
}
size_t to_write = sz;
Float32 *dataL = (Float32 *)self->cnv_buffer;
Float32 *dataR = (Float32 *)(self->cnv_buffer + to_write);
sz /= sizeof(Float32);
for (unsigned int i = 0; i < sz; i++) {
dataL[i] = data[i];
dataR[i] = data[i];
}
size_t len = jack_ringbuffer_write(self->rb[0], (char *)dataL, to_write);
if (len < to_write) {
Reporter::reportEvent( 1, "failed to write to ring buffer");
err = true;
}
len = jack_ringbuffer_write(self->rb[1], (char *)dataR, to_write);
if (len < to_write) {
Reporter::reportEvent( 1, "failed to write to ring buffer");
err = true;
}
#endif
} else if (self->getChannel() == 1 && self->stream_description.mChannelsPerFrame == 1) {
#if 1
Reporter::reportEvent( 1, "not supported.");
err = true;
#else
//XXX not tested.
size_t to_write = inInputData->mBuffers[0].mDataByteSize;
size_t len = jack_ringbuffer_write(self->rb[0], (char *)data, to_write);
if (len < to_write) {
Reporter::reportEvent( 1, "failed to write to ring buffer");
err = true;
}
#endif
} else {
Reporter::reportEvent( 1, "not reach here.");
err = true;
}
}
if (err) {
return kAudioHardwareUnspecifiedError;
}
// Success
return kAudioHardwareNoError;
}
/*
*/
OSStatus
CoreAudioDspSource :: device_listener( AudioDeviceID inDevice,
UInt32 channel,
Boolean isInput,
AudioDevicePropertyID propertyID,
void* handlePointer)
{
#if 0
CoreAudioDspSource* self = (CoreAudioDspSource*)handlePointer;
if ( propertyID == kAudioDeviceProcessorOverload ) {
Reporter::reportEvent( 1, "CoreAudioDspSource :: device_listener xrun");
// xrun!
}
#endif
return kAudioHardwareNoError;
}
/*
*/
static unsigned int get_device_count(void)
{
unsigned int count = 0;
UInt32 data_size = 0;
OSStatus result = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &data_size, NULL);
if (result != noErr) {
Reporter::reportEvent( 1, "CoreAudioDspSource :: get_device_count():error:",
get_error_name(result));
return 0;
}
count = data_size / sizeof(AudioDeviceID);
return count;
}
/*
*/
bool CoreAudioDspSource :: startDevice()
{
if (is_running) {
return true;
}
OSStatus result = AudioDeviceAddIOProc(device_id, callback_handler, this);
if (result != noErr) {
Reporter::reportEvent( 1, "CoreAudioDspSource :: startDevice():error:AudioDeviceAddIOProc():",
get_error_name(result));
return false;
}
result = AudioDeviceStart(device_id, callback_handler);
if (result != noErr) {
Reporter::reportEvent( 1, "CoreAudioDspSource :: startDevice():error:AudioDeviceStart():",
get_error_name(result));
return false;
}
is_running = true;
return true;
}
/*
*/
bool CoreAudioDspSource :: stopDevice()
{
if (!is_running) {
return true;
}
OSStatus result = AudioDeviceRemoveIOProc(device_id, callback_handler);
if (result != noErr) {
#if 0
Reporter::reportEvent( 1, "CoreAudioDspSource :: stopDevice():error:AudioDeviceRemoveIOProc():",
get_error_name(result));
return false;
#endif
}
result = AudioDeviceStop(device_id, callback_handler);
if (result != noErr) {
#if 0
Reporter::reportEvent( 1, "CoreAudioDspSource :: stopDevice():error:AudioDeviceStop():",
get_error_name(result));
return false;
#endif
}
is_running = false;
return true;
}
static const char* get_error_name( OSStatus code )
{
switch( code ) {
case kAudioHardwareNotRunningError:
return "kAudioHardwareNotRunningError";
case kAudioHardwareUnspecifiedError:
return "kAudioHardwareUnspecifiedError";
case kAudioHardwareUnknownPropertyError:
return "kAudioHardwareUnknownPropertyError";
case kAudioHardwareBadPropertySizeError:
return "kAudioHardwareBadPropertySizeError";
case kAudioHardwareIllegalOperationError:
return "kAudioHardwareIllegalOperationError";
#if 0
case kAudioHardwareBadObjectError:
return "kAudioHardwareBadObjectError";
#endif
case kAudioHardwareBadDeviceError:
return "kAudioHardwareBadDeviceError";
case kAudioHardwareBadStreamError:
return "kAudioHardwareBadStreamError";
case kAudioHardwareUnsupportedOperationError:
return "kAudioHardwareUnsupportedOperationError";
case kAudioDeviceUnsupportedFormatError:
return "kAudioDeviceUnsupportedFormatError";
case kAudioDevicePermissionsError:
return "kAudioDevicePermissionsError";
default:
return "CoreAudio unknown error";
}
}
#endif // SUPPORT_COREAUDIO_DSP

View File

@ -0,0 +1,271 @@
#ifndef COREAUDIO_DSP_SOURCE_H
#define COREAUDIO_DSP_SOURCE_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#include "Reporter.h"
#include "AudioSource.h"
#if defined( HAVE_COREAUDIO_LIB )
#include <jack/ringbuffer.h>
#include <CoreAudio/CoreAudio.h>
#else
#error configure for CoreAudio
#endif
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* An audio input based on CoreAudio
*
* @author $Author: $
* @version $Revision: $
*/
class CoreAudioDspSource : public AudioSource, public virtual Reporter
{
private:
/**
* The device ID
*/
AudioDeviceID device_id;
/**
* The ring buffer.
*/
jack_ringbuffer_t * rb[2];
/**
* The audio sample buffer.
*/
char * tmp_buffer;
/**
* The audio format convarting buffer.
*/
char * cnv_buffer;
/**
* Device status whether running or not.
*/
bool is_running;
/**
* Device status whether be opened or not.
*/
bool is_opened;
/**
* Stream description.
*/
AudioStreamBasicDescription stream_description;
protected:
/**
* Default constructor. Always throws an Exception.
*
* @exception Exception
*/
inline
CoreAudioDspSource ( void ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__);
}
/**
* Initialize the object
*
* @exception Exception
*/
void
init ( const char* name ) throw ( Exception );
/**
* De-initialize the object
*
* @exception Exception
*/
void
strip ( void ) throw ( Exception );
static OSStatus
callback_handler( AudioDeviceID inDevice,
const AudioTimeStamp *inNow,
const AudioBufferList *inInputData,
const AudioTimeStamp *inInputTime,
AudioBufferList *outOutputData,
const AudioTimeStamp *inOutputTime,
void *infoPointer );
static OSStatus
device_listener( AudioDeviceID inDevice,
UInt32 channel,
Boolean isInput,
AudioDevicePropertyID propertyID,
void* handlePointer);
private:
/**
*/
bool
startDevice(void);
/**
*/
bool
stopDevice(void);
public:
/**
* Constructor.
*
* @param name the name of the device
* @param sampleRate samples per second (e.g. 44100 for 44.1kHz).
* @param bitsPerSample bits per sample (e.g. 16 bits).
* @param channels number of channels of the audio source
* (e.g. 1 for mono, 2 for stereo, etc.).
* @exception Exception
*/
inline
CoreAudioDspSource ( const char * name,
int sampleRate = 44100,
int bitsPerSample = 16,
int channels = 2 )
throw ( Exception )
: AudioSource( sampleRate, bitsPerSample, channels )
{
init( name );
}
/**
* Copy Constructor.
*
* @param cds the object to copy.
* @exception Exception
*/
inline
CoreAudioDspSource ( const CoreAudioDspSource & cds ) throw ( Exception )
: AudioSource( cds )
{
throw Exception( __FILE__, __LINE__, "CoreAudioDspSource doesn't copy");
}
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~CoreAudioDspSource ( void ) throw ( Exception )
{
strip();
}
/**
* Assignment operator.
*
* @param ds the object to assign to this one.
* @return a reference to this object.
* @exception Exception
*/
inline virtual CoreAudioDspSource &
operator= ( const CoreAudioDspSource & ds ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__, "CoreAudioDspSource doesn't assign");
}
/**
* Tell if the data from this source comes in big or little endian.
*
* @return true if the source is big endian, false otherwise
*/
virtual bool
isBigEndian ( void ) const throw ();
/**
* Open the CoreAudioDspSource.
* This does not put the device into recording mode.
* To start getting samples, call either canRead() or read().
*
* @return true if opening was successful, false otherwise
* @exception Exception
*
* @see #canRead
* @see #read
*/
virtual bool
open ( void ) throw ( Exception );
/**
* Check if the CoreAudioDspSource is registered
*
* @return true if device is setup
*/
inline virtual bool
isOpen ( void ) const throw ()
{
return is_opened;
}
/**
* Check if the CoreAudioDspSource can be read from.
* Blocks until the specified time for data to be available.
* Puts the CoreAudio device into recording mode.
*
* @param sec the maximum seconds to block.
* @param usec micro seconds to block after the full seconds.
* @return true if the CoreAudioDspSource is ready to be read from,
* false otherwise.
* @exception Exception
*/
virtual bool
canRead ( unsigned int sec,
unsigned int usec ) throw ( Exception );
/**
* Read from the CoreAudioDspSource.
* Puts the CoreAudio device into recording mode.
*
* @param buf the buffer to read into.
* @param len the number of bytes to read into buf
* @return the number of bytes read (may be less than len).
* @exception Exception
*/
virtual unsigned int
read ( void * buf,
unsigned int len ) throw ( Exception );
/**
* Close the CoreAudioDspSource.
*
* @exception Exception
*/
virtual void
close ( void ) throw ( Exception );
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* COREAUDIO_DSP_SOURCE_H */

View File

@ -1191,7 +1191,7 @@ DarkIce :: encode ( void ) throw ( Exception )
(dsp->getBitsPerSample() / 8UL) *
dsp->getChannel() *
duration;
len = encConnector->transfer( bytes, 4096, 1, 0 );
reportEvent( 1, len, "bytes transfered to the encoders");

View File

@ -3,7 +3,7 @@ AM_CXXFLAGS = -O2 -pedantic -Wall @DEBUG_CXXFLAGS@ @PTHREAD_CFLAGS@
@JACK_CFLAGS@
INCLUDES = @LAME_INCFLAGS@ @VORBIS_INCFLAGS@ @FAAC_INCFLAGS@ @AACPLUS_INCFLAGS@ @TWOLAME_INCFLAGS@ @ALSA_INCFLAGS@
LDADD = @PTHREAD_LIBS@ @LAME_LDFLAGS@ @VORBIS_LDFLAGS@ @FAAC_LDFLAGS@ @AACPLUS_LDFLAGS@ @TWOLAME_LDFLAGS@ \
@ALSA_LDFLAGS@ @JACK_LDFLAGS@
@ALSA_LDFLAGS@ @JACK_LDFLAGS@ @COREAUDIO_LDFLAGS@
darkice_SOURCES = AudioEncoder.h\
AudioSource.h\
@ -70,5 +70,7 @@ darkice_SOURCES = AudioEncoder.h\
AlsaDspSource.cpp\
JackDspSource.h\
JackDspSource.cpp\
CoreAudioDspSource.h\
CoreAudioDspSource.cpp\
main.cpp