* THE SOFTWARE.
*/
+/*
+ * Implemented audio-in
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ * Contact:
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ */
+
#include "qemu/osdep.h"
#include <CoreAudio/CoreAudio.h>
#include <pthread.h> /* pthread_X */
int nbuffers;
} CoreaudioConf;
-typedef struct coreaudioVoiceOut {
- HWVoiceOut hw;
+typedef struct coreaudioVoice {
pthread_mutex_t mutex;
- AudioDeviceID outputDeviceID;
+ AudioDeviceID deviceID;
UInt32 audioDevicePropertyBufferFrameSize;
- AudioStreamBasicDescription outputStreamBasicDescription;
+ AudioStreamBasicDescription description;
AudioDeviceIOProcID ioprocid;
int live;
int decr;
- int rpos;
+ int pos;
+} coreaudioVoice;
+
+typedef struct coreaudioVoiceOut {
+ HWVoiceOut hw;
+ coreaudioVoice core[1];
} coreaudioVoiceOut;
+typedef struct coreaudioVoiceIn {
+ HWVoiceIn hw;
+ coreaudioVoice core[1];
+} coreaudioVoiceIn;
+
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
/* The APIs used here only become available from 10.6 */
-static OSStatus coreaudio_get_voice(AudioDeviceID *id)
+static OSStatus coreaudio_get_voice(AudioDeviceID *id, bool isInput)
{
UInt32 size = sizeof(*id);
AudioObjectPropertyAddress addr = {
- kAudioHardwarePropertyDefaultOutputDevice,
+ isInput ? kAudioHardwarePropertyDefaultInputDevice : kAudioHardwarePropertyDefaultOutputDevice,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster
};
}
static OSStatus coreaudio_get_framesizerange(AudioDeviceID id,
- AudioValueRange *framerange)
+ AudioValueRange *framerange, bool isInput)
{
UInt32 size = sizeof(*framerange);
AudioObjectPropertyAddress addr = {
kAudioDevicePropertyBufferFrameSizeRange,
- kAudioDevicePropertyScopeOutput,
+ isInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
kAudioObjectPropertyElementMaster
};
framerange);
}
-static OSStatus coreaudio_get_framesize(AudioDeviceID id, UInt32 *framesize)
+static OSStatus coreaudio_get_framesize(AudioDeviceID id, UInt32 *framesize, bool isInput)
{
UInt32 size = sizeof(*framesize);
AudioObjectPropertyAddress addr = {
kAudioDevicePropertyBufferFrameSize,
- kAudioDevicePropertyScopeOutput,
+ isInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
kAudioObjectPropertyElementMaster
};
framesize);
}
-static OSStatus coreaudio_set_framesize(AudioDeviceID id, UInt32 *framesize)
+static OSStatus coreaudio_set_framesize(AudioDeviceID id, UInt32 *framesize, bool isInput)
{
UInt32 size = sizeof(*framesize);
AudioObjectPropertyAddress addr = {
kAudioDevicePropertyBufferFrameSize,
- kAudioDevicePropertyScopeOutput,
+ isInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
kAudioObjectPropertyElementMaster
};
}
static OSStatus coreaudio_get_streamformat(AudioDeviceID id,
- AudioStreamBasicDescription *d)
+ AudioStreamBasicDescription *d, bool isInput)
{
UInt32 size = sizeof(*d);
AudioObjectPropertyAddress addr = {
kAudioDevicePropertyStreamFormat,
- kAudioDevicePropertyScopeOutput,
+ isInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
kAudioObjectPropertyElementMaster
};
}
static OSStatus coreaudio_set_streamformat(AudioDeviceID id,
- AudioStreamBasicDescription *d)
+ AudioStreamBasicDescription *d, bool isInput)
{
UInt32 size = sizeof(*d);
AudioObjectPropertyAddress addr = {
kAudioDevicePropertyStreamFormat,
- kAudioDevicePropertyScopeOutput,
+ isInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
kAudioObjectPropertyElementMaster
};
#else
/* Legacy versions of functions using deprecated APIs */
-static OSStatus coreaudio_get_voice(AudioDeviceID *id)
+static OSStatus coreaudio_get_voice(AudioDeviceID *id, bool isInput)
{
UInt32 size = sizeof(*id);
return AudioHardwareGetProperty(
- kAudioHardwarePropertyDefaultOutputDevice,
+ isInput ? kAudioHardwarePropertyDefaultInputDevice : kAudioHardwarePropertyDefaultOutputDevice,
&size,
id);
}
static OSStatus coreaudio_get_framesizerange(AudioDeviceID id,
- AudioValueRange *framerange)
+ AudioValueRange *framerange, bool isInput)
{
UInt32 size = sizeof(*framerange);
return AudioDeviceGetProperty(
id,
0,
- 0,
+ isInput,
kAudioDevicePropertyBufferFrameSizeRange,
&size,
framerange);
}
-static OSStatus coreaudio_get_framesize(AudioDeviceID id, UInt32 *framesize)
+static OSStatus coreaudio_get_framesize(AudioDeviceID id, UInt32 *framesize, bool isInput)
{
UInt32 size = sizeof(*framesize);
return AudioDeviceGetProperty(
id,
0,
- false,
+ isInput,
kAudioDevicePropertyBufferFrameSize,
&size,
framesize);
}
-static OSStatus coreaudio_set_framesize(AudioDeviceID id, UInt32 *framesize)
+static OSStatus coreaudio_set_framesize(AudioDeviceID id, UInt32 *framesize, bool isInput)
{
UInt32 size = sizeof(*framesize);
id,
NULL,
0,
- false,
+ isInput,
kAudioDevicePropertyBufferFrameSize,
size,
framesize);
}
static OSStatus coreaudio_get_streamformat(AudioDeviceID id,
- AudioStreamBasicDescription *d)
+ AudioStreamBasicDescription *d, bool isInput)
{
UInt32 size = sizeof(*d);
return AudioDeviceGetProperty(
id,
0,
- false,
+ isInput,
kAudioDevicePropertyStreamFormat,
&size,
d);
}
static OSStatus coreaudio_set_streamformat(AudioDeviceID id,
- AudioStreamBasicDescription *d)
+ AudioStreamBasicDescription *d, bool isInput)
{
UInt32 size = sizeof(*d);
id,
0,
0,
- 0,
+ isInput,
kAudioDevicePropertyStreamFormat,
size,
d);
coreaudio_logstatus (status);
}
-static inline UInt32 isPlaying (AudioDeviceID outputDeviceID)
+static inline UInt32 isPlaying (AudioDeviceID deviceID)
{
OSStatus status;
UInt32 result = 0;
- status = coreaudio_get_isrunning(outputDeviceID, &result);
+ status = coreaudio_get_isrunning(deviceID, &result);
if (status != kAudioHardwareNoError) {
coreaudio_logerr(status,
"Could not determine whether Device is playing\n");
isAtexit = 1;
}
-static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name)
+static int coreaudio_lock (coreaudioVoice *core, const char *fn_name)
{
int err;
return 0;
}
-static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
+static int coreaudio_unlock (coreaudioVoice *core, const char *fn_name)
{
int err;
return 0;
}
-static int coreaudio_run_out (HWVoiceOut *hw, int live)
-{
- int decr;
- coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
-
- if (coreaudio_lock (core, "coreaudio_run_out")) {
- return 0;
- }
-
- if (core->decr > live) {
- ldebug ("core->decr %d live %d core->live %d\n",
- core->decr,
- live,
- core->live);
- }
-
- decr = audio_MIN (core->decr, live);
- core->decr -= decr;
-
- core->live = live - decr;
- hw->rpos = core->rpos;
-
- coreaudio_unlock (core, "coreaudio_run_out");
- return decr;
-}
-
-/* callback to feed audiooutput buffer */
-static OSStatus audioDeviceIOProc(
- AudioDeviceID inDevice,
- const AudioTimeStamp* inNow,
- const AudioBufferList* inInputData,
- const AudioTimeStamp* inInputTime,
- AudioBufferList* outOutputData,
- const AudioTimeStamp* inOutputTime,
- void* hwptr)
-{
- UInt32 frame, frameCount;
- float *out = outOutputData->mBuffers[0].mData;
- HWVoiceOut *hw = hwptr;
- coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
- int rpos, live;
- struct st_sample *src;
-#ifndef FLOAT_MIXENG
-#ifdef RECIPROCAL
- const float scale = 1.f / UINT_MAX;
-#else
- const float scale = UINT_MAX;
-#endif
-#endif
-
- if (coreaudio_lock (core, "audioDeviceIOProc")) {
- inInputTime = 0;
- return 0;
- }
-
- frameCount = core->audioDevicePropertyBufferFrameSize;
- live = core->live;
-
- /* if there are not enough samples, set signal and return */
- if (live < frameCount) {
- inInputTime = 0;
- coreaudio_unlock (core, "audioDeviceIOProc(empty)");
- return 0;
- }
-
- rpos = core->rpos;
- src = hw->mix_buf + rpos;
-
- /* fill buffer */
- for (frame = 0; frame < frameCount; frame++) {
-#ifdef FLOAT_MIXENG
- *out++ = src[frame].l; /* left channel */
- *out++ = src[frame].r; /* right channel */
-#else
-#ifdef RECIPROCAL
- *out++ = src[frame].l * scale; /* left channel */
- *out++ = src[frame].r * scale; /* right channel */
-#else
- *out++ = src[frame].l / scale; /* left channel */
- *out++ = src[frame].r / scale; /* right channel */
-#endif
-#endif
- }
-
- rpos = (rpos + frameCount) % hw->samples;
- core->decr += frameCount;
- core->rpos = rpos;
-
- coreaudio_unlock (core, "audioDeviceIOProc");
- return 0;
-}
-
-static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
-{
- return audio_pcm_sw_write (sw, buf, len);
-}
-
-static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
- void *drv_opaque)
+static int coreaudio_init_voice (coreaudioVoice *core, void *hw, struct audsettings *as,
+ CoreaudioConf *conf, AudioDeviceIOProc inProc, bool isInput)
{
OSStatus status;
- coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
int err;
- const char *typ = "playback";
+ const char *typ = isInput ? "capture" : "playback";
AudioValueRange frameRange;
- CoreaudioConf *conf = drv_opaque;
/* create mutex */
err = pthread_mutex_init(&core->mutex, NULL);
return -1;
}
- audio_pcm_init_info (&hw->info, as);
-
- status = coreaudio_get_voice(&core->outputDeviceID);
+ status = coreaudio_get_voice(&core->deviceID, isInput);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ,
- "Could not get default output Device\n");
+ "Could not get default device\n");
return -1;
}
- if (core->outputDeviceID == kAudioDeviceUnknown) {
+ if (core->deviceID == kAudioDeviceUnknown) {
dolog ("Could not initialize %s - Unknown Audiodevice\n", typ);
return -1;
}
/* get minimum and maximum buffer frame sizes */
- status = coreaudio_get_framesizerange(core->outputDeviceID,
- &frameRange);
+ status = coreaudio_get_framesizerange(core->deviceID,
+ &frameRange, isInput);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ,
"Could not get device buffer frame range\n");
}
/* set Buffer Frame Size */
- status = coreaudio_set_framesize(core->outputDeviceID,
- &core->audioDevicePropertyBufferFrameSize);
+ status = coreaudio_set_framesize(core->deviceID,
+ &core->audioDevicePropertyBufferFrameSize, isInput);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ,
"Could not set device buffer frame size %" PRIu32 "\n",
}
/* get Buffer Frame Size */
- status = coreaudio_get_framesize(core->outputDeviceID,
- &core->audioDevicePropertyBufferFrameSize);
+ status = coreaudio_get_framesize(core->deviceID,
+ &core->audioDevicePropertyBufferFrameSize, isInput);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ,
"Could not get device buffer frame size\n");
return -1;
}
- hw->samples = conf->nbuffers * core->audioDevicePropertyBufferFrameSize;
/* get StreamFormat */
- status = coreaudio_get_streamformat(core->outputDeviceID,
- &core->outputStreamBasicDescription);
+ status = coreaudio_get_streamformat(core->deviceID,
+ &core->description, isInput);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ,
"Could not get Device Stream properties\n");
- core->outputDeviceID = kAudioDeviceUnknown;
+ core->deviceID = kAudioDeviceUnknown;
return -1;
}
/* set Samplerate */
- core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
- status = coreaudio_set_streamformat(core->outputDeviceID,
- &core->outputStreamBasicDescription);
+ core->description.mSampleRate = (Float64) as->freq;
+ status = coreaudio_set_streamformat(core->deviceID,
+ &core->description, isInput);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n",
as->freq);
- core->outputDeviceID = kAudioDeviceUnknown;
+ core->deviceID = kAudioDeviceUnknown;
return -1;
}
/* set Callback */
core->ioprocid = NULL;
- status = AudioDeviceCreateIOProcID(core->outputDeviceID,
- audioDeviceIOProc,
+ status = AudioDeviceCreateIOProcID(core->deviceID,
+ inProc,
hw,
&core->ioprocid);
if (status != kAudioHardwareNoError || core->ioprocid == NULL) {
coreaudio_logerr2 (status, typ, "Could not set IOProc\n");
- core->outputDeviceID = kAudioDeviceUnknown;
+ core->deviceID = kAudioDeviceUnknown;
return -1;
}
- /* start Playback */
- if (!isPlaying(core->outputDeviceID)) {
- status = AudioDeviceStart(core->outputDeviceID, core->ioprocid);
+ /* start Playback/Capture */
+ if (!isPlaying(core->deviceID)) {
+ status = AudioDeviceStart(core->deviceID, core->ioprocid);
if (status != kAudioHardwareNoError) {
- coreaudio_logerr2 (status, typ, "Could not start playback\n");
- AudioDeviceDestroyIOProcID(core->outputDeviceID, core->ioprocid);
- core->outputDeviceID = kAudioDeviceUnknown;
+ coreaudio_logerr2 (status, typ, "Could not start %s\n", typ);
+ AudioDeviceDestroyIOProcID(core->deviceID, core->ioprocid);
+ core->deviceID = kAudioDeviceUnknown;
return -1;
}
}
return 0;
}
-static void coreaudio_fini_out (HWVoiceOut *hw)
+static void coreaudio_fini_voice (coreaudioVoice *core, bool isInput)
{
OSStatus status;
+ const char *typ = isInput ? "capture" : "playback";
int err;
- coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
if (!isAtexit) {
- /* stop playback */
- if (isPlaying(core->outputDeviceID)) {
- status = AudioDeviceStop(core->outputDeviceID, core->ioprocid);
+ /* stop playback/capture */
+ if (isPlaying(core->deviceID)) {
+ status = AudioDeviceStop(core->deviceID, core->ioprocid);
if (status != kAudioHardwareNoError) {
- coreaudio_logerr (status, "Could not stop playback\n");
+ coreaudio_logerr (status, "Could not stop %s\n", typ);
}
}
- /* remove callback */
- status = AudioDeviceDestroyIOProcID(core->outputDeviceID,
+ /* remove callback/capture */
+ status = AudioDeviceDestroyIOProcID(core->deviceID,
core->ioprocid);
if (status != kAudioHardwareNoError) {
coreaudio_logerr (status, "Could not remove IOProc\n");
}
}
- core->outputDeviceID = kAudioDeviceUnknown;
+ core->deviceID = kAudioDeviceUnknown;
/* destroy mutex */
err = pthread_mutex_destroy(&core->mutex);
}
}
-static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
+static int coreaudio_ctl_voice (coreaudioVoice *core, int cmd, bool isInput)
{
OSStatus status;
- coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
+ const char *typ = isInput ? "capture" : "playback";
switch (cmd) {
case VOICE_ENABLE:
- /* start playback */
- if (!isPlaying(core->outputDeviceID)) {
- status = AudioDeviceStart(core->outputDeviceID, core->ioprocid);
+ /* start playback/capture */
+ if (!isPlaying(core->deviceID)) {
+ status = AudioDeviceStart(core->deviceID, core->ioprocid);
if (status != kAudioHardwareNoError) {
- coreaudio_logerr (status, "Could not resume playback\n");
+ coreaudio_logerr (status, "Could not resume %s\n", typ);
}
}
break;
case VOICE_DISABLE:
- /* stop playback */
+ /* stop playback/capture */
if (!isAtexit) {
- if (isPlaying(core->outputDeviceID)) {
- status = AudioDeviceStop(core->outputDeviceID,
+ if (isPlaying(core->deviceID)) {
+ status = AudioDeviceStop(core->deviceID,
core->ioprocid);
if (status != kAudioHardwareNoError) {
- coreaudio_logerr (status, "Could not pause playback\n");
+ coreaudio_logerr (status, "Could not pause %s\n", typ);
}
}
}
return 0;
}
+static int coreaudio_run_out (HWVoiceOut *hw, int live)
+{
+ int decr;
+ coreaudioVoice *core = ((coreaudioVoiceOut *) hw)->core;
+
+ if (coreaudio_lock (core, "coreaudio_run_out")) {
+ return 0;
+ }
+
+ if (core->decr > live) {
+ ldebug ("core->decr %d live %d core->live %d\n",
+ core->decr,
+ live,
+ core->live);
+ }
+
+ decr = audio_MIN (core->decr, live);
+ core->decr -= decr;
+
+ core->live = live - decr;
+ hw->rpos = core->pos;
+
+ coreaudio_unlock (core, "coreaudio_run_out");
+ return decr;
+}
+
+/* callback to feed audiooutput buffer */
+static OSStatus audioOutDeviceIOProc(
+ AudioDeviceID inDevice,
+ const AudioTimeStamp* inNow,
+ const AudioBufferList* inInputData,
+ const AudioTimeStamp* inInputTime,
+ AudioBufferList* outOutputData,
+ const AudioTimeStamp* inOutputTime,
+ void* hwptr)
+{
+ UInt32 frame, frameCount;
+ float *out = outOutputData->mBuffers[0].mData;
+ HWVoiceOut *hw = hwptr;
+ coreaudioVoice *core = ((coreaudioVoiceOut *) hw)->core;
+ int rpos, live;
+ struct st_sample *src;
+#ifndef FLOAT_MIXENG
+#ifdef RECIPROCAL
+ const float scale = 1.f / UINT_MAX;
+#else
+ const float scale = UINT_MAX;
+#endif
+#endif
+
+ if (coreaudio_lock (core, "audioDeviceIOProc")) {
+ inInputTime = 0;
+ return 0;
+ }
+
+ frameCount = core->audioDevicePropertyBufferFrameSize;
+ live = core->live;
+
+ /* if there are not enough samples, set signal and return */
+ if (live < frameCount) {
+ inInputTime = 0;
+ coreaudio_unlock (core, "audioDeviceIOProc(empty)");
+ return 0;
+ }
+
+ rpos = core->pos;
+ src = hw->mix_buf + rpos;
+
+ /* fill buffer */
+ for (frame = 0; frame < frameCount; frame++) {
+#ifdef FLOAT_MIXENG
+ *out++ = src[frame].l; /* left channel */
+ *out++ = src[frame].r; /* right channel */
+#else
+#ifdef RECIPROCAL
+ *out++ = src[frame].l * scale; /* left channel */
+ *out++ = src[frame].r * scale; /* right channel */
+#else
+ *out++ = src[frame].l / scale; /* left channel */
+ *out++ = src[frame].r / scale; /* right channel */
+#endif
+#endif
+ }
+
+ rpos = (rpos + frameCount) % hw->samples;
+ core->decr += frameCount;
+ core->pos = rpos;
+
+ coreaudio_unlock (core, "audioDeviceIOProc");
+ return 0;
+}
+
+static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
+{
+ return audio_pcm_sw_write (sw, buf, len);
+}
+
+static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
+ void *drv_opaque)
+{
+ coreaudioVoice *core = ((coreaudioVoiceOut *) hw)->core;
+ CoreaudioConf *conf = drv_opaque;
+
+ if (coreaudio_init_voice(core, hw, as, conf, audioOutDeviceIOProc, false) < 0) {
+ return -1;
+ }
+
+ audio_pcm_init_info (&hw->info, as);
+ hw->samples = conf->nbuffers * core->audioDevicePropertyBufferFrameSize;
+
+ return 0;
+}
+
+static void coreaudio_fini_out (HWVoiceOut *hw)
+{
+ coreaudioVoice *core = ((coreaudioVoiceOut *) hw)->core;
+
+ coreaudio_fini_voice(core, false);
+}
+
+static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
+{
+ coreaudioVoice *core = ((coreaudioVoiceOut *) hw)->core;
+
+ return coreaudio_ctl_voice (core, cmd, false);
+}
+
+static int coreaudio_run_in (HWVoiceIn *hw)
+{
+ int decr;
+ coreaudioVoice *core = ((coreaudioVoiceIn *) hw)->core;
+
+ if (coreaudio_lock (core, "coreaudio_run_in")) {
+ return 0;
+ }
+
+ decr = core->decr;
+ core->decr -= decr;
+ hw->wpos = core->pos;
+
+ coreaudio_unlock (core, "coreaudio_run_in");
+ return decr;
+}
+
+/* callback to feed audiooutput buffer */
+static OSStatus audioInDeviceIOProc(
+ AudioDeviceID inDevice,
+ const AudioTimeStamp* inNow,
+ const AudioBufferList* inInputData,
+ const AudioTimeStamp* inInputTime,
+ AudioBufferList* outOutputData,
+ const AudioTimeStamp* inOutputTime,
+ void* hwptr)
+{
+ UInt32 frame, frameCount;
+ float *in = inInputData->mBuffers[0].mData;
+ HWVoiceIn *hw = hwptr;
+ coreaudioVoice *core = ((coreaudioVoiceIn *) hw)->core;
+ int wpos, avail;
+ struct st_sample *dst;
+#ifndef FLOAT_MIXENG
+#ifdef RECIPROCAL
+ const float scale = 1.f / UINT_MAX;
+#else
+ const float scale = UINT_MAX;
+#endif
+#endif
+
+ if (coreaudio_lock (core, "audioDeviceIOProc")) {
+ inInputTime = 0;
+ return 0;
+ }
+
+ frameCount = core->audioDevicePropertyBufferFrameSize;
+ avail = hw->samples - hw->total_samples_captured - core->decr;
+
+ /* if there are not enough samples, set signal and return */
+ if (avail < frameCount) {
+ inInputTime = 0;
+ coreaudio_unlock (core, "audioDeviceIOProc(empty)");
+ return 0;
+ }
+
+ wpos = core->pos;
+ dst = hw->conv_buf + wpos;
+
+ /* fill buffer */
+ for (frame = 0; frame < frameCount; frame++) {
+#ifdef FLOAT_MIXENG
+ dst[frame].l = *in++; /* left channel */
+ dst[frame].r = *in++; /* right channel */
+#else
+#ifdef RECIPROCAL
+ dst[frame].l = *in++ * scale; /* left channel */
+ dst[frame].r = *in++ * scale; /* right channel */
+#else
+ dst[frame].l = *in++ / scale; /* left channel */
+ dst[frame].r = *in++ / scale; /* right channel */
+#endif
+#endif
+ }
+
+ wpos = (wpos + frameCount) % hw->samples;
+ core->decr += frameCount;
+ core->pos = wpos;
+
+
+ coreaudio_unlock (core, "audioDeviceIOProc");
+ return 0;
+}
+
+static int coreaudio_read (SWVoiceIn *sw, void *buf, int len)
+{
+ return audio_pcm_sw_read (sw, buf, len);
+}
+
+static int coreaudio_init_in(HWVoiceIn *hw, struct audsettings *as,
+ void *drv_opaque)
+{
+ coreaudioVoice *core = ((coreaudioVoiceIn *) hw)->core;
+ CoreaudioConf *conf = drv_opaque;
+
+ if (coreaudio_init_voice(core, hw, as, conf, audioInDeviceIOProc, true) < 0) {
+ return -1;
+ }
+
+ audio_pcm_init_info (&hw->info, as);
+ hw->samples = conf->nbuffers * core->audioDevicePropertyBufferFrameSize;
+
+ return 0;
+}
+
+static void coreaudio_fini_in (HWVoiceIn *hw)
+{
+ coreaudioVoice *core = ((coreaudioVoiceIn *) hw)->core;
+
+ coreaudio_fini_voice(core, true);
+}
+
+static int coreaudio_ctl_in (HWVoiceIn *hw, int cmd, ...)
+{
+ coreaudioVoice *core = ((coreaudioVoiceIn *) hw)->core;
+
+ return coreaudio_ctl_voice (core, cmd, true);
+}
+
static CoreaudioConf glob_conf = {
.buffer_frames = 512,
.nbuffers = 4,
.fini_out = coreaudio_fini_out,
.run_out = coreaudio_run_out,
.write = coreaudio_write,
- .ctl_out = coreaudio_ctl_out
+ .ctl_out = coreaudio_ctl_out,
+
+ .init_in = coreaudio_init_in,
+ .fini_in = coreaudio_fini_in,
+ .run_in = coreaudio_run_in,
+ .read = coreaudio_read,
+ .ctl_in = coreaudio_ctl_in,
};
struct audio_driver coreaudio_audio_driver = {
.pcm_ops = &coreaudio_pcm_ops,
.can_be_default = 1,
.max_voices_out = 1,
- .max_voices_in = 0,
+ .max_voices_in = 1,
.voice_size_out = sizeof (coreaudioVoiceOut),
- .voice_size_in = 0
+ .voice_size_in = sizeof (coreaudioVoiceIn),
};