VirtualBox

Changeset 25770 in vbox


Ignore:
Timestamp:
Jan 12, 2010 4:17:04 PM (15 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
56528
Message:

Audio-OSX: Rewrite of the CoreAudio device. Added recording support.

Location:
trunk/src/VBox/Devices
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Audio/DevIchAc97.cpp

    r23981 r25770  
    16611661    ac97Reset (pDevIns);
    16621662
    1663 #ifndef RT_OS_DARWIN /* coreaudio doesn't supply these. */
    16641663    if (!s->voice_pi)
    16651664        LogRel (("AC97: WARNING: Unable to open PCM IN!\n"));
    16661665    if (!s->voice_mc)
    16671666        LogRel (("AC97: WARNING: Unable to open PCM MC!\n"));
    1668 #endif
    16691667    if (!s->voice_po)
    16701668        LogRel (("AC97: WARNING: Unable to open PCM OUT!\n"));
     
    16861684                "with the consequence that no sound is audible"));
    16871685    }
    1688 #ifndef RT_OS_DARWIN
    16891686    else if (!s->voice_pi || !s->voice_po || !s->voice_mc)
    16901687    {
     
    17041701                "subsystem"), szMissingVoices);
    17051702    }
    1706 #endif
    17071703
    17081704    return VINF_SUCCESS;
  • trunk/src/VBox/Devices/Audio/coreaudio.c

    r1584 r25770  
     1/* $Id$ */
     2/** @file
     3 * VBox audio devices: Mac OS X CoreAudio audio driver
     4 */
     5
    16/*
    2  * QEMU OS X CoreAudio audio driver
    3  *
    47 * Copyright (c) 2005 Mike Kronenberg
    58 *
     
    2326 */
    2427
     28#define LOG_GROUP LOG_GROUP_DEV_AUDIO
     29#include <VBox/log.h>
     30#include <iprt/mem.h>
     31#include <iprt/cdefs.h>
     32
     33#define AUDIO_CAP "coreaudio"
     34#include "vl_vbox.h"
     35#include "audio.h"
     36#include "audio_int.h"
     37
    2538#include <CoreAudio/CoreAudio.h>
    26 #include <string.h>             /* strerror */
    27 #include <pthread.h>            /* pthread_X */
    28 
    29 #ifndef VBOX
    30 #include "vl.h"
    31 #else
    32 # include "vl_vbox.h"
    33 # include "audio.h"
    34 #endif
    35 
    36 #define AUDIO_CAP "coreaudio"
    37 #include "audio_int.h"
    38 
    39 struct {
    40     int buffer_frames;
    41     int nbuffers;
    42     int isAtexit;
    43 } conf = {
    44     .buffer_frames = 512,
    45     .nbuffers = 4,
    46     .isAtexit = 0
     39#include <AudioUnit/AudioUnit.h>
     40
     41/* todo:
     42 * - checking for properties changes of the devices
     43 * - set frame size (use config)
     44 * - AudioUnit converter for changing the sample rate
     45 * - maybe get rid of the extra input sample buffer
     46 * - maybe make sure the thread is immediately stopped if playing/recording stops
     47 */
     48
     49/* Most of this is based on:
     50 * http://developer.apple.com/mac/library/technotes/tn2004/tn2097.html
     51 * http://developer.apple.com/mac/library/technotes/tn2002/tn2091.html
     52 * http://developer.apple.com/mac/library/documentation/AudioUnit/Reference/AUComponentServicesReference/Reference/reference.html
     53 */
     54
     55/*******************************************************************************
     56 *
     57 * IO Ring Buffer section
     58 *
     59 ******************************************************************************/
     60
     61/* Implementation of a lock free ring buffer which could be used in a multi
     62 * threaded environment. */
     63typedef struct IORINGBUFFER
     64{
     65    /* The current read position in the buffer */
     66    uint32_t uReadPos;
     67    /* The current write position in the buffer */
     68    uint32_t uWritePos;
     69    /* How much space of the buffer is currently in use */
     70    volatile uint32_t cBufferUsed;
     71    /* How big is the buffer */
     72    uint32_t cBufSize;
     73    /* The buffer itself */
     74    char *pBuffer;
     75} IORINGBUFFER;
     76/* Pointer to an ring buffer structure */
     77typedef IORINGBUFFER* PIORINGBUFFER;
     78
     79
     80static void IORingBufferCreate(PIORINGBUFFER *ppBuffer, uint32_t cSize)
     81{
     82    PIORINGBUFFER pTmpBuffer;
     83
     84    AssertPtr(ppBuffer);
     85
     86    *ppBuffer = NULL;
     87    pTmpBuffer = RTMemAllocZ(sizeof(IORINGBUFFER));
     88    if (pTmpBuffer)
     89    {
     90        pTmpBuffer->pBuffer = RTMemAlloc(cSize);
     91        if(pTmpBuffer->pBuffer)
     92        {
     93            pTmpBuffer->cBufSize = cSize;
     94            *ppBuffer = pTmpBuffer;
     95        }
     96        else
     97            RTMemFree(pTmpBuffer);
     98    }
     99}
     100
     101static void IORingBufferDestroy(PIORINGBUFFER pBuffer)
     102{
     103    if (pBuffer)
     104    {
     105        if (pBuffer->pBuffer)
     106            RTMemFree(pBuffer->pBuffer);
     107        RTMemFree(pBuffer);
     108    }
     109}
     110
     111DECL_FORCE_INLINE(void) IORingBufferReset(PIORINGBUFFER pBuffer)
     112{
     113    AssertPtr(pBuffer);
     114
     115    pBuffer->uReadPos = 0;
     116    pBuffer->uWritePos = 0;
     117    pBuffer->cBufferUsed = 0;
     118}
     119
     120DECL_FORCE_INLINE(uint32_t) IORingBufferFree(PIORINGBUFFER pBuffer)
     121{
     122    AssertPtr(pBuffer);
     123    return pBuffer->cBufSize - pBuffer->cBufferUsed;
     124}
     125
     126DECL_FORCE_INLINE(uint32_t) IORingBufferUsed(PIORINGBUFFER pBuffer)
     127{
     128    AssertPtr(pBuffer);
     129    return pBuffer->cBufferUsed;
     130}
     131
     132static void IORingBufferAquireReadBlock(PIORINGBUFFER pBuffer, uint32_t cReqSize, char **ppStart, uint32_t *pcSize)
     133{
     134    uint32_t uUsed = 0;
     135    uint32_t uSize = 0;
     136
     137    AssertPtr(pBuffer);
     138
     139    *ppStart = 0;
     140    *pcSize = 0;
     141
     142    /* How much is in use? */
     143    uUsed = ASMAtomicAddU32(&pBuffer->cBufferUsed, 0);
     144    if (uUsed > 0)
     145    {
     146        /* Get the size out of the requested size, the read block till the end
     147         * of the buffer & the currently used size. */
     148        uSize = RT_MIN(cReqSize, RT_MIN(pBuffer->cBufSize - pBuffer->uReadPos, uUsed));
     149        if (uSize > 0)
     150        {
     151            /* Return the pointer address which point to the current read
     152             * position. */
     153            *ppStart = pBuffer->pBuffer + pBuffer->uReadPos;
     154            *pcSize = uSize;
     155        }
     156    }
     157}
     158
     159DECL_FORCE_INLINE(void) IORingBufferReleaseReadBlock(PIORINGBUFFER pBuffer, uint32_t cSize)
     160{
     161    AssertPtr(pBuffer);
     162
     163    /* Split at the end of the buffer. */
     164    pBuffer->uReadPos = (pBuffer->uReadPos + cSize) % pBuffer->cBufSize;
     165
     166    ASMAtomicSubU32((int32_t*)&pBuffer->cBufferUsed, cSize);
     167}
     168
     169static void IORingBufferAquireWriteBlock(PIORINGBUFFER pBuffer, uint32_t cReqSize, char **ppStart, uint32_t *pcSize)
     170{
     171    uint32_t uFree;
     172    uint32_t uSize;
     173
     174    AssertPtr(pBuffer);
     175
     176    *ppStart = 0;
     177    *pcSize = 0;
     178
     179    /* How much is free? */
     180    uFree = pBuffer->cBufSize - ASMAtomicAddU32(&pBuffer->cBufferUsed, 0);
     181    if (uFree > 0)
     182    {
     183        /* Get the size out of the requested size, the write block till the end
     184         * of the buffer & the currently free size. */
     185        uSize = RT_MIN(cReqSize, RT_MIN(pBuffer->cBufSize - pBuffer->uWritePos, uFree));
     186        if (uSize > 0)
     187        {
     188            /* Return the pointer address which point to the current write
     189             * position. */
     190            *ppStart = pBuffer->pBuffer + pBuffer->uWritePos;
     191            *pcSize = uSize;
     192        }
     193    }
     194}
     195
     196DECL_FORCE_INLINE(void) IORingBufferReleaseWriteBlock(PIORINGBUFFER pBuffer, uint32_t cSize)
     197{
     198    AssertPtr(pBuffer);
     199
     200    /* Split at the end of the buffer. */
     201    pBuffer->uWritePos = (pBuffer->uWritePos + cSize) % pBuffer->cBufSize;
     202
     203    ASMAtomicAddU32(&pBuffer->cBufferUsed, cSize);
     204}
     205
     206/*******************************************************************************
     207 *
     208 * Helper function section
     209 *
     210 ******************************************************************************/
     211
     212#if DEBUG
     213static void caDebugOutputAudioStreamBasicDescription(const char *pszDesc, const AudioStreamBasicDescription *pStreamDesc)
     214{
     215    char pszSampleRate[32];
     216    Log(("%s AudioStreamBasicDescription:\n", pszDesc));
     217    Log(("CoreAudio: Format ID: %RU32 (%c%c%c%c)\n", pStreamDesc->mFormatID, RT_BYTE4(pStreamDesc->mFormatID), RT_BYTE3(pStreamDesc->mFormatID), RT_BYTE2(pStreamDesc->mFormatID), RT_BYTE1(pStreamDesc->mFormatID)));
     218    Log(("CoreAudio: Flags: %RU32", pStreamDesc->mFormatFlags));
     219    if (pStreamDesc->mFormatFlags & kAudioFormatFlagIsFloat)
     220        Log((" Float"));
     221    if (pStreamDesc->mFormatFlags & kAudioFormatFlagIsBigEndian)
     222        Log((" BigEndian"));
     223    if (pStreamDesc->mFormatFlags & kAudioFormatFlagIsSignedInteger)
     224        Log((" SignedInteger"));
     225    if (pStreamDesc->mFormatFlags & kAudioFormatFlagIsPacked)
     226        Log((" Packed"));
     227    if (pStreamDesc->mFormatFlags & kAudioFormatFlagIsAlignedHigh)
     228        Log((" AlignedHigh"));
     229    if (pStreamDesc->mFormatFlags & kAudioFormatFlagIsNonInterleaved)
     230        Log((" NonInterleaved"));
     231    if (pStreamDesc->mFormatFlags & kAudioFormatFlagIsNonMixable)
     232        Log((" NonMixable"));
     233    if (pStreamDesc->mFormatFlags & kAudioFormatFlagsAreAllClear)
     234        Log((" AllClear"));
     235    Log(("\n"));
     236    snprintf(pszSampleRate, 32, "%.2f", (float)pStreamDesc->mSampleRate);
     237    Log(("CoreAudio: SampleRate: %s\n", pszSampleRate));
     238    Log(("CoreAudio: ChannelsPerFrame: %RU32\n", pStreamDesc->mChannelsPerFrame));
     239    Log(("CoreAudio: FramesPerPacket: %RU32\n", pStreamDesc->mFramesPerPacket));
     240    Log(("CoreAudio: BitsPerChannel: %RU32\n", pStreamDesc->mBitsPerChannel));
     241    Log(("CoreAudio: BytesPerFrame: %RU32\n", pStreamDesc->mBytesPerFrame));
     242    Log(("CoreAudio: BytesPerPacket: %RU32\n", pStreamDesc->mBytesPerPacket));
     243}
     244#endif /* DEBUG */
     245
     246static void caAudioSettingsToAudioStreamBasicDescription(const audsettings_t *pAS, AudioStreamBasicDescription *pStreamDesc)
     247{
     248    pStreamDesc->mFormatID = kAudioFormatLinearPCM;
     249    pStreamDesc->mFormatFlags = kAudioFormatFlagIsPacked;
     250    pStreamDesc->mFramesPerPacket = 1;
     251    pStreamDesc->mSampleRate = (Float64)pAS->freq;
     252    pStreamDesc->mChannelsPerFrame = pAS->nchannels;
     253    switch (pAS->fmt)
     254    {
     255        case AUD_FMT_U8:
     256            {
     257                pStreamDesc->mBitsPerChannel = 8;
     258                break;
     259            }
     260        case AUD_FMT_S8:
     261            {
     262                pStreamDesc->mBitsPerChannel = 8;
     263                pStreamDesc->mFormatFlags |= kAudioFormatFlagIsSignedInteger;
     264                break;
     265            }
     266        case AUD_FMT_U16:
     267            {
     268                pStreamDesc->mBitsPerChannel = 16;
     269                break;
     270            }
     271        case AUD_FMT_S16:
     272            {
     273                pStreamDesc->mBitsPerChannel = 16;
     274                pStreamDesc->mFormatFlags |= kAudioFormatFlagIsSignedInteger;
     275                break;
     276            }
     277#ifdef PA_SAMPLE_S32LE
     278        case AUD_FMT_U32:
     279            {
     280                pStreamDesc->mBitsPerChannel = 32;
     281                break;
     282            }
     283        case AUD_FMT_S32:
     284            {
     285                pStreamDesc->mBitsPerChannel = 32;
     286                pStreamDesc->mFormatFlags |= kAudioFormatFlagIsSignedInteger;
     287                break;
     288            }
     289#endif
     290        default:
     291            break;
     292    }
     293    pStreamDesc->mBytesPerFrame = pStreamDesc->mChannelsPerFrame * (pStreamDesc->mBitsPerChannel / 8);
     294    pStreamDesc->mBytesPerPacket = pStreamDesc->mFramesPerPacket * pStreamDesc->mBytesPerFrame;
     295}
     296
     297DECL_FORCE_INLINE(bool) caIsRunning(AudioDeviceID deviceID)
     298{
     299    OSStatus err = noErr;
     300    UInt32 uFlag = 0;
     301    UInt32 uSize = sizeof(uFlag);
     302    err = AudioDeviceGetProperty(deviceID,
     303                                 0,
     304                                 0,
     305                                 kAudioDevicePropertyDeviceIsRunning,
     306                                 &uSize,
     307                                 &uFlag);
     308    if (err != kAudioHardwareNoError)
     309        LogRel(("CoreAudio: Could not determine whether the device is running (%RI32)\n", err));
     310    return uFlag >= 1;
     311}
     312
     313/*******************************************************************************
     314 *
     315 * Global structures section
     316 *
     317 ******************************************************************************/
     318
     319struct
     320{
     321    int cBufferFrames;
     322} conf =
     323{
     324    INIT_FIELD(.cBufferFrames =) 512
    47325};
    48326
    49 typedef struct coreaudioVoiceOut {
     327typedef struct caVoiceOut
     328{
     329    /* HW voice output struture defined by VBox */
    50330    HWVoiceOut hw;
    51     pthread_mutex_t mutex;
    52     int isAtexit;
    53     AudioDeviceID outputDeviceID;
    54     UInt32 audioDevicePropertyBufferFrameSize;
    55     AudioStreamBasicDescription outputStreamBasicDescription;
    56     int live;
    57     int decr;
    58     int rpos;
    59 } coreaudioVoiceOut;
    60 
    61 static void coreaudio_logstatus (OSStatus status)
    62 {
    63     char *str = "BUG";
    64 
    65     switch(status) {
    66     case kAudioHardwareNoError:
    67         str = "kAudioHardwareNoError";
    68         break;
    69 
    70     case kAudioHardwareNotRunningError:
    71         str = "kAudioHardwareNotRunningError";
    72         break;
    73 
    74     case kAudioHardwareUnspecifiedError:
    75         str = "kAudioHardwareUnspecifiedError";
    76         break;
    77 
    78     case kAudioHardwareUnknownPropertyError:
    79         str = "kAudioHardwareUnknownPropertyError";
    80         break;
    81 
    82     case kAudioHardwareBadPropertySizeError:
    83         str = "kAudioHardwareBadPropertySizeError";
    84         break;
    85 
    86     case kAudioHardwareIllegalOperationError:
    87         str = "kAudioHardwareIllegalOperationError";
    88         break;
    89 
    90     case kAudioHardwareBadDeviceError:
    91         str = "kAudioHardwareBadDeviceError";
    92         break;
    93 
    94     case kAudioHardwareBadStreamError:
    95         str = "kAudioHardwareBadStreamError";
    96         break;
    97 
    98     case kAudioHardwareUnsupportedOperationError:
    99         str = "kAudioHardwareUnsupportedOperationError";
    100         break;
    101 
    102     case kAudioDeviceUnsupportedFormatError:
    103         str = "kAudioDeviceUnsupportedFormatError";
    104         break;
    105 
    106     case kAudioDevicePermissionsError:
    107         str = "kAudioDevicePermissionsError";
    108         break;
    109 
    110     default:
    111         AUD_log (AUDIO_CAP, "Reason: status code %ld\n", status);
    112         return;
    113     }
    114 
    115     AUD_log (AUDIO_CAP, "Reason: %s\n", str);
    116 }
    117 
    118 static void GCC_FMT_ATTR (2, 3) coreaudio_logerr (
    119     OSStatus status,
    120     const char *fmt,
    121     ...
    122     )
    123 {
    124     va_list ap;
    125 
    126     va_start (ap, fmt);
    127     AUD_log (AUDIO_CAP, fmt, ap);
    128     va_end (ap);
    129 
    130     coreaudio_logstatus (status);
    131 }
    132 
    133 static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
    134     OSStatus status,
    135     const char *typ,
    136     const char *fmt,
    137     ...
    138     )
    139 {
    140     va_list ap;
    141 
    142     AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
    143 
    144     va_start (ap, fmt);
    145     AUD_vlog (AUDIO_CAP, fmt, ap);
    146     va_end (ap);
    147 
    148     coreaudio_logstatus (status);
    149 }
    150 
    151 static inline UInt32 isPlaying (AudioDeviceID outputDeviceID)
    152 {
    153     OSStatus status;
    154     UInt32 result = 0;
    155     UInt32 propertySize = sizeof(outputDeviceID);
    156     status = AudioDeviceGetProperty(
    157         outputDeviceID, 0, 0,
    158         kAudioDevicePropertyDeviceIsRunning, &propertySize, &result);
    159     if (status != kAudioHardwareNoError) {
    160         coreaudio_logerr(status,
    161                          "Could not determine whether Device is playing\n");
    162     }
    163     return result;
    164 }
    165 
    166 static void coreaudio_atexit (void)
    167 {
    168     conf.isAtexit = 1;
    169 }
    170 
    171 static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name)
    172 {
    173     int err;
    174 
    175     err = pthread_mutex_lock (&core->mutex);
    176     if (err) {
    177         dolog ("Could not lock voice for %s\nReason: %s\n",
    178                fn_name, strerror (err));
    179         return -1;
    180     }
     331    /* Stream description which is default on the device */
     332    AudioStreamBasicDescription deviceFormat;
     333    /* Stream description which is selected for using by VBox */
     334    AudioStreamBasicDescription streamFormat;
     335    /* The audio device ID of the currently used device */
     336    AudioDeviceID audioDeviceId;
     337    /* The AudioUnit used */
     338    AudioUnit audioUnit;
     339    /* A ring buffer for transfering data to the playback thread */
     340    PIORINGBUFFER pBuf;
     341} caVoiceOut;
     342
     343typedef struct caVoiceIn
     344{
     345    /* HW voice input struture defined by VBox */
     346    HWVoiceIn hw;
     347    /* Stream description which is default on the device */
     348    AudioStreamBasicDescription deviceFormat;
     349    /* Stream description which is selected for using by VBox */
     350    AudioStreamBasicDescription streamFormat;
     351    /* The audio device ID of the currently used device */
     352    AudioDeviceID audioDeviceId;
     353    /* The AudioUnit used */
     354    AudioUnit audioUnit;
     355    /* An extra buffer used for render the audio data in the recording thread */
     356    AudioBufferList *pcaBufferList;
     357    /* A ring buffer for transfering from to the recording thread */
     358    PIORINGBUFFER pBuf;
     359} caVoiceIn;
     360
     361
     362/*******************************************************************************
     363 *
     364 * CoreAudio output section
     365 *
     366 ******************************************************************************/
     367
     368/* callback to feed audiooutput buffer */
     369static OSStatus caPlaybackCallback(void* inRefCon,
     370                                   AudioUnitRenderActionFlags* ioActionFlags,
     371                                   const AudioTimeStamp* inTimeStamp,
     372                                   UInt32 inBusNumber,
     373                                   UInt32 inNumberFrames,
     374                                   AudioBufferList* ioData)
     375{
     376    uint32_t csAvail = 0;
     377    uint32_t cbToRead = 0;
     378    uint32_t csToRead = 0;
     379    uint32_t csReads = 0;
     380    char *pcSrc = NULL;
     381
     382    caVoiceOut *caVoice = (caVoiceOut *) inRefCon;
     383
     384    /* How much space is used in the ring buffer? */
     385    csAvail = IORingBufferUsed(caVoice->pBuf) >> caVoice->hw.info.shift; /* bytes -> samples */
     386    /* How much space is available in the core audio buffer. Use the smaller
     387     * size of the too. */
     388    csAvail = RT_MIN(csAvail, ioData->mBuffers[0].mDataByteSize >> caVoice->hw.info.shift);
     389
     390    Log2(("CoreAudio: [Output] Start reading buffer with %RU32 samples (%RU32 bytes)\n", csAvail, csAvail << caVoice->hw.info.shift));
     391
     392    /* Iterate as long as data is available */
     393    while(csReads < csAvail)
     394    {
     395        /* How much is left? */
     396        csToRead = csAvail - csReads;
     397        cbToRead = csToRead << caVoice->hw.info.shift; /* samples -> bytes */
     398        Log2(("CoreAudio: [Output] Try reading %RU32 samples (%RU32 bytes)\n", csToRead, cbToRead));
     399        /* Try to aquire the necessary block from the ring buffer. */
     400        IORingBufferAquireReadBlock(caVoice->pBuf, cbToRead, &pcSrc, &cbToRead);
     401        /* How much to we get? */
     402        csToRead = cbToRead >> caVoice->hw.info.shift; /* bytes -> samples */
     403        Log2(("CoreAudio: [Output] There are %RU32 samples (%RU32 bytes) available\n", csToRead, cbToRead));
     404        /* Break if nothing is used anymore. */
     405        if (RT_UNLIKELY(cbToRead == 0))
     406            break;
     407        /* Copy the data from our ring buffer to the core audio buffer. */
     408        memcpy((char*)ioData->mBuffers[0].mData + (csReads << caVoice->hw.info.shift), pcSrc, cbToRead);
     409        /* Release the read buffer, so it could be used for new data. */
     410        IORingBufferReleaseReadBlock(caVoice->pBuf, cbToRead);
     411        /* How much have we reads so far. */
     412        csReads += csToRead;
     413    }
     414    /* Write the bytes to the core audio buffer which where really written. */
     415    ioData->mBuffers[0].mDataByteSize = csReads << caVoice->hw.info.shift; /* samples -> bytes */
     416
     417    Log2(("CoreAudio: [Output] Finished reading buffer with %RU32 samples (%RU32 bytes)\n", csReads, csReads << caVoice->hw.info.shift));
     418
     419    return noErr;
     420}
     421
     422static int coreaudio_run_out(HWVoiceOut *hw)
     423{
     424    uint32_t csAvail = 0;
     425    uint32_t cbToWrite = 0;
     426    uint32_t csToWrite = 0;
     427    uint32_t csWritten = 0;
     428    char *pcDst = NULL;
     429    st_sample_t *psSrc = NULL;
     430
     431    caVoiceOut *caVoice = (caVoiceOut *) hw;
     432
     433    /* How much space is available in the ring buffer */
     434    csAvail = IORingBufferFree(caVoice->pBuf) >> hw->info.shift; /* bytes -> samples */
     435    /* How much data is availabe. Use the smaller size of the too. */
     436    csAvail = RT_MIN(csAvail, (uint32_t)audio_pcm_hw_get_live_out(hw));
     437
     438    Log2(("CoreAudio: [Output] Start writing buffer with %RU32 samples (%RU32 bytes)\n", csAvail, csAvail << hw->info.shift));
     439
     440    /* Iterate as long as data is available */
     441    while (csWritten < csAvail)
     442    {
     443        /* How much is left? Split request at the end of our samples buffer. */
     444        csToWrite = RT_MIN(csAvail - csWritten, (uint32_t)(hw->samples - hw->rpos));
     445        cbToWrite = csToWrite << hw->info.shift; /* samples -> bytes */
     446        Log2(("CoreAudio: [Output] Try writing %RU32 samples (%RU32 bytes)\n", csToWrite, cbToWrite));
     447        /* Try to aquire the necessary space from the ring buffer. */
     448        IORingBufferAquireWriteBlock(caVoice->pBuf, cbToWrite, &pcDst, &cbToWrite);
     449        /* How much to we get? */
     450        csToWrite = cbToWrite >> hw->info.shift;
     451        Log2(("CoreAudio: [Output] There is space for %RU32 samples (%RU32 bytes) available\n", csToWrite, cbToWrite));
     452        /* Break if nothing is free anymore. */
     453        if (RT_UNLIKELY(cbToWrite == 0))
     454            break;
     455        /* Copy the data from our mix buffer to the ring buffer. */
     456        psSrc = hw->mix_buf + hw->rpos;
     457        hw->clip((uint8_t*)pcDst, psSrc, csToWrite);
     458        /* Release the ring buffer, so the read thread could start reading this data. */
     459        IORingBufferReleaseWriteBlock(caVoice->pBuf, cbToWrite);
     460        hw->rpos = (hw->rpos + csToWrite) % hw->samples;
     461        /* How much have we written so far. */
     462        csWritten += csToWrite;
     463    }
     464
     465    Log2(("CoreAudio: [Output] Finished writing buffer with %RU32 samples (%RU32 bytes)\n", csWritten, csWritten << hw->info.shift));
     466
     467    /* Return the count of samples we have processed. */
     468    return csWritten;
     469}
     470
     471static int coreaudio_write(SWVoiceOut *sw, void *buf, int len)
     472{
     473    return audio_pcm_sw_write (sw, buf, len);
     474}
     475
     476static int coreaudio_init_out(HWVoiceOut *hw, audsettings_t *as)
     477{
     478    OSStatus err = noErr;
     479    UInt32 uSize = 0; /* temporary size of properties */
     480    UInt32 uFlag = 0; /* for setting flags */
     481    CFStringRef name; /* for the temporary device name fetching */
     482    const char *pszName;
     483    ComponentDescription cd; /* description for an audio component */
     484    Component cp; /* an audio component */
     485    AURenderCallbackStruct cb; /* holds the callback structure */
     486    UInt32 cFrames; /* default frame count */
     487
     488    caVoiceOut *caVoice = (caVoiceOut *) hw;
     489
     490    /* Initialize the hardware info section with the audio settings */
     491    audio_pcm_init_info(&hw->info, as);
     492
     493    /* Fetch the default audio output device currently in use */
     494    uSize = sizeof(caVoice->audioDeviceId);
     495    err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
     496                                   &uSize,
     497                                   &caVoice->audioDeviceId);
     498    if (RT_UNLIKELY(err != noErr))
     499    {
     500        LogRel(("CoreAudio: [Output] Unable to find default output device (%RI32)\n", err));
     501        return -1;
     502    }
     503
     504    /* Try to get the name of the default output device and log it. It's not
     505     * fatal if it fails. */
     506    uSize = sizeof(CFStringRef);
     507    err = AudioDeviceGetProperty(caVoice->audioDeviceId,
     508                                 0,
     509                                 0,
     510                                 kAudioObjectPropertyName,
     511                                 &uSize,
     512                                 &name);
     513    if (RT_LIKELY(err == noErr))
     514    {
     515        pszName = CFStringGetCStringPtr(name, kCFStringEncodingMacRoman);
     516        if (pszName)
     517            LogRel(("CoreAudio: Using default output device: %s\n", pszName));
     518        CFRelease(name);
     519    }
     520    else
     521        LogRel(("CoreAudio: [Output] Unable to get output device name (%RI32)\n", err));
     522
     523    cd.componentType = kAudioUnitType_Output;
     524    cd.componentSubType = kAudioUnitSubType_HALOutput;
     525    cd.componentManufacturer = kAudioUnitManufacturer_Apple;
     526    cd.componentFlags = 0;
     527    cd.componentFlagsMask = 0;
     528
     529    /* Try to find the default HAL output component. */
     530    cp = FindNextComponent(NULL, &cd);
     531    if (RT_UNLIKELY(cp == 0))
     532    {
     533        LogRel(("CoreAudio: [Output] Failed to find HAL output component\n"));
     534        return -1;
     535    }
     536
     537    /* Open the default HAL output component. */
     538    err = OpenAComponent(cp, &caVoice->audioUnit);
     539    if (RT_UNLIKELY(err != noErr))
     540    {
     541        LogRel(("CoreAudio: [Output] Failed to open output component (%RI32)\n", err));
     542        return -1;
     543    }
     544
     545    /* Switch the I/O mode for output to on. */
     546    uFlag = 1;
     547    err = AudioUnitSetProperty(caVoice->audioUnit,
     548                               kAudioOutputUnitProperty_EnableIO,
     549                               kAudioUnitScope_Output,
     550                               0,
     551                               &uFlag,
     552                               sizeof(uFlag));
     553    if (RT_UNLIKELY(err != noErr))
     554    {
     555        LogRel(("CoreAudio: [Output] Failed to set output I/O mode enabled (%RI32)\n", err));
     556        return -1;
     557    }
     558
     559    /* CoreAudio will inform us on a second thread when it needs more data for
     560     * output. Therfor register an callback function which will provide the new
     561     * data. */
     562    cb.inputProc = caPlaybackCallback;
     563    cb.inputProcRefCon = caVoice;
     564
     565    err = AudioUnitSetProperty(caVoice->audioUnit,
     566                               kAudioUnitProperty_SetRenderCallback,
     567                               kAudioUnitScope_Global,
     568                               0,
     569                               &cb,
     570                               sizeof(cb));
     571    if (RT_UNLIKELY(err != noErr))
     572    {
     573        LogRel(("CoreAudio: [Output] Failed to set callback (%RI32)\n", err));
     574        return -1;
     575    }
     576
     577    /* Set the default audio output device as the device for the new AudioUnit. */
     578    err = AudioUnitSetProperty(caVoice->audioUnit,
     579                               kAudioOutputUnitProperty_CurrentDevice,
     580                               kAudioUnitScope_Global,
     581                               0,
     582                               &caVoice->audioDeviceId,
     583                               sizeof(caVoice->audioDeviceId));
     584    if (RT_UNLIKELY(err != noErr))
     585    {
     586        LogRel(("CoreAudio: [Output] Failed to set current device (%RI32)\n", err));
     587        return -1;
     588    }
     589
     590    /* Fetch the current stream format of the device. */
     591    uSize = sizeof(caVoice->deviceFormat);
     592    err = AudioUnitGetProperty(caVoice->audioUnit,
     593                               kAudioUnitProperty_StreamFormat,
     594                               kAudioUnitScope_Input,
     595                               0,
     596                               &caVoice->deviceFormat,
     597                               &uSize);
     598    if (RT_UNLIKELY(err != noErr))
     599    {
     600        LogRel(("CoreAudio: [Output] Failed to get device format (%RI32)\n", err));
     601        return -1;
     602    }
     603
     604    /* Create an AudioStreamBasicDescription based on the audio settings of
     605     * VirtualBox. */
     606    caAudioSettingsToAudioStreamBasicDescription(as, &caVoice->streamFormat);
     607
     608#if DEBUG
     609    caDebugOutputAudioStreamBasicDescription("CoreAudio: [Output] device", &caVoice->deviceFormat);
     610    caDebugOutputAudioStreamBasicDescription("CoreAudio: [Output] output", &caVoice->streamFormat);
     611#endif /* DEBUG */
     612
     613    /* Set the device format description for the stream. */
     614    err = AudioUnitSetProperty(caVoice->audioUnit,
     615                               kAudioUnitProperty_StreamFormat,
     616                               kAudioUnitScope_Input,
     617                               0,
     618                               &caVoice->streamFormat,
     619                               sizeof(caVoice->streamFormat));
     620    if (RT_UNLIKELY(err != noErr))
     621    {
     622        LogRel(("CoreAudio: [Output] Failed to set stream format (%RI32)\n", err));
     623        return -1;
     624    }
     625
     626    /* Get the default frames buffer size, so that we can setup our internal
     627     * buffers. */
     628    uSize = sizeof(cFrames);
     629    err = AudioUnitGetProperty(caVoice->audioUnit,
     630                               kAudioDevicePropertyBufferFrameSize,
     631                               kAudioUnitScope_Output,
     632                               0,
     633                               &cFrames,
     634                               &uSize);
     635    if (RT_UNLIKELY(err != noErr))
     636    {
     637        LogRel(("CoreAudio: [Output] Failed to get frame buffer size (%RI32)\n", err));
     638        return -1;
     639    }
     640
     641/*    cFrames = 1024;*/
     642/*    err = AudioUnitSetProperty(caVoice->audioUnit,*/
     643/*                               kAudioDevicePropertyBufferFrameSize,*/
     644/*                               kAudioUnitScope_Output,*/
     645/*                               0,*/
     646/*                               &cFrames,*/
     647/*                               sizeof(cFrames));*/
     648/*    if (RT_UNLIKELY(err != noErr))*/
     649/*    {*/
     650/*        LogRel(("CoreAudio: [Output] Failed to set frame buffer size (%RI32)\n", err));*/
     651/*        return -1;*/
     652/*    }*/
     653
     654    /* Finaly init the new AudioUnit. */
     655    err = AudioUnitInitialize(caVoice->audioUnit);
     656    if (RT_UNLIKELY(err != noErr))
     657    {
     658        LogRel(("CoreAudio: [Output] Failed to initialize the AudioUnit (%RI32)\n", err));
     659        return -1;
     660    }
     661
     662    /* Create the internal ring buffer. */
     663    hw->samples = cFrames * caVoice->streamFormat.mChannelsPerFrame;
     664    IORingBufferCreate(&caVoice->pBuf, hw->samples << hw->info.shift);
     665    if (!VALID_PTR(caVoice->pBuf))
     666    {
     667        LogRel(("CoreAudio: [Output] Failed to create internal ring buffer\n"));
     668        AudioUnitUninitialize(caVoice->audioUnit);
     669        return -1;
     670    }
     671
     672    Log(("CoreAudio: [Output] HW samples: %d; Frame count: %RU32\n", hw->samples, cFrames));
     673
    181674    return 0;
    182675}
    183676
    184 static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
    185 {
    186     int err;
    187 
    188     err = pthread_mutex_unlock (&core->mutex);
    189     if (err) {
    190         dolog ("Could not unlock voice for %s\nReason: %s\n",
    191                fn_name, strerror (err));
    192         return -1;
     677static void coreaudio_fini_out(HWVoiceOut *hw)
     678{
     679    OSStatus err = noErr;
     680    caVoiceOut *caVoice = (caVoiceOut *) hw;
     681
     682    /* Only stop the device if it is actually running */
     683    if (caIsRunning(caVoice->audioDeviceId))
     684        err = AudioOutputUnitStop(caVoice->audioUnit);
     685    if (RT_LIKELY(err == noErr))
     686    {
     687        err = AudioUnitUninitialize(caVoice->audioUnit);
     688        if (RT_LIKELY(err == noErr))
     689        {
     690            caVoice->audioDeviceId = kAudioDeviceUnknown;
     691            IORingBufferDestroy(caVoice->pBuf);
     692        }
     693        else
     694            LogRel(("CoreAudio: [Output] Failed to uninitialize the AudioUnit (%RI32)\n", err));
     695    }
     696    else
     697        LogRel(("CoreAudio: [Output] Failed to stop playback (%RI32)\n", err));
     698}
     699
     700static int coreaudio_ctl_out(HWVoiceOut *hw, int cmd, ...)
     701{
     702    OSStatus err = noErr;
     703    caVoiceOut *caVoice = (caVoiceOut *) hw;
     704
     705    switch (cmd)
     706    {
     707        case VOICE_ENABLE:
     708            {
     709                /* Only start the device if it is actually stopped */
     710                if (!caIsRunning(caVoice->audioDeviceId))
     711                {
     712                    IORingBufferReset(caVoice->pBuf);
     713                    err = AudioOutputUnitStart(caVoice->audioUnit);
     714                }
     715                if (RT_UNLIKELY(err != noErr))
     716                {
     717                    LogRel(("CoreAudio: [Output] Failed to start playback (%RI32)\n", err));
     718                    return -1;
     719                }
     720                break;
     721            }
     722        case VOICE_DISABLE:
     723            {
     724                /* Only stop the device if it is actually running */
     725                if (caIsRunning(caVoice->audioDeviceId))
     726                    err = AudioOutputUnitStop(caVoice->audioUnit);
     727                if (RT_UNLIKELY(err != noErr))
     728                {
     729                    LogRel(("CoreAudio: [Input] Failed to stop playback (%RI32)\n", err));
     730                    return -1;
     731                }
     732                break;
     733            }
    193734    }
    194735    return 0;
    195736}
    196737
    197 static int coreaudio_run_out (HWVoiceOut *hw)
    198 {
    199     int live, decr;
    200     coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
    201 
    202     if (coreaudio_lock (core, "coreaudio_run_out")) {
    203         return 0;
    204     }
    205 
    206     live = audio_pcm_hw_get_live_out (hw);
    207 
    208     if (core->decr > live) {
    209         ldebug ("core->decr %d live %d core->live %d\n",
    210                 core->decr,
    211                 live,
    212                 core->live);
    213     }
    214 
    215     decr = audio_MIN (core->decr, live);
    216     core->decr -= decr;
    217 
    218     core->live = live - decr;
    219     hw->rpos = core->rpos;
    220 
    221     coreaudio_unlock (core, "coreaudio_run_out");
    222     return decr;
    223 }
    224 
    225 /* callback to feed audiooutput buffer */
    226 static OSStatus audioDeviceIOProc(
    227     AudioDeviceID inDevice,
    228     const AudioTimeStamp* inNow,
    229     const AudioBufferList* inInputData,
    230     const AudioTimeStamp* inInputTime,
    231     AudioBufferList* outOutputData,
    232     const AudioTimeStamp* inOutputTime,
    233     void* hwptr)
    234 {
    235     UInt32 frame, frameCount;
    236     float *out = outOutputData->mBuffers[0].mData;
    237     HWVoiceOut *hw = hwptr;
    238     coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
    239     int rpos, live;
    240     st_sample_t *src;
    241 #ifndef FLOAT_MIXENG
    242 #ifdef RECIPROCAL
    243     const float scale = 1.f / UINT_MAX;
    244 #else
    245     const float scale = UINT_MAX;
    246 #endif
    247 #endif
    248 
    249     if (coreaudio_lock (core, "audioDeviceIOProc")) {
    250         inInputTime = 0;
    251         return 0;
    252     }
    253 
    254     frameCount = core->audioDevicePropertyBufferFrameSize;
    255     live = core->live;
    256 
    257     /* if there are not enough samples, set signal and return */
    258     if (live < frameCount) {
    259         inInputTime = 0;
    260         coreaudio_unlock (core, "audioDeviceIOProc(empty)");
    261         return 0;
    262     }
    263 
    264     rpos = core->rpos;
    265     src = hw->mix_buf + rpos;
    266 
    267     /* fill buffer */
    268     for (frame = 0; frame < frameCount; frame++) {
    269 #ifdef FLOAT_MIXENG
    270         *out++ = src[frame].l; /* left channel */
    271         *out++ = src[frame].r; /* right channel */
    272 #else
    273 #ifdef RECIPROCAL
    274         *out++ = src[frame].l * scale; /* left channel */
    275         *out++ = src[frame].r * scale; /* right channel */
    276 #else
    277         *out++ = src[frame].l / scale; /* left channel */
    278         *out++ = src[frame].r / scale; /* right channel */
    279 #endif
    280 #endif
    281     }
    282 
    283     rpos = (rpos + frameCount) % hw->samples;
    284     core->decr += frameCount;
    285     core->rpos = rpos;
    286 
    287     coreaudio_unlock (core, "audioDeviceIOProc");
     738/*******************************************************************************
     739 *
     740 * CoreAudio input section
     741 *
     742 ******************************************************************************/
     743
     744/* callback to feed audio input buffer */
     745static OSStatus caRecordingCallback(void* inRefCon,
     746                                    AudioUnitRenderActionFlags* ioActionFlags,
     747                                    const AudioTimeStamp* inTimeStamp,
     748                                    UInt32 inBusNumber,
     749                                    UInt32 inNumberFrames,
     750                                    AudioBufferList* ioData)
     751{
     752    OSStatus err = noErr;
     753    uint32_t csAvail = 0;
     754    uint32_t csToWrite = 0;
     755    uint32_t cbToWrite = 0;
     756    uint32_t csWritten = 0;
     757    char *pcDst = NULL;
     758
     759    caVoiceIn *caVoice = (caVoiceIn *) inRefCon;
     760
     761    /* If nothing is pending return immediately. */
     762    if (inNumberFrames == 0)
     763        return noErr;
     764
     765    caVoice->pcaBufferList->mBuffers[0].mDataByteSize = caVoice->streamFormat.mBytesPerFrame * inNumberFrames;
     766    caVoice->pcaBufferList->mBuffers[0].mData = RTMemAlloc(caVoice->pcaBufferList->mBuffers[0].mDataByteSize);
     767
     768    err = AudioUnitRender(caVoice->audioUnit,
     769                          ioActionFlags,
     770                          inTimeStamp,
     771                          inBusNumber,
     772                          inNumberFrames,
     773                          caVoice->pcaBufferList);
     774    if(RT_UNLIKELY(err != noErr))
     775    {
     776        Log(("CoreAudio: [Input] Failed to render audio data (%RI32)\n", err));
     777        RTMemFree(caVoice->pcaBufferList->mBuffers[0].mData);
     778        return err;
     779    }
     780
     781    /* How much space is free in the ring buffer? */
     782    csAvail = IORingBufferFree(caVoice->pBuf) >> caVoice->hw.info.shift; /* bytes -> samples */
     783    /* How much space is used in the core audio buffer. Use the smaller size of
     784     * the too. */
     785    csAvail = RT_MIN(csAvail, caVoice->pcaBufferList->mBuffers[0].mDataByteSize >> caVoice->hw.info.shift);
     786
     787    Log2(("CoreAudio: [Input] Start writing buffer with %RU32 samples (%RU32 bytes)\n", csAvail, csAvail << caVoice->hw.info.shift));
     788
     789    /* Iterate as long as data is available */
     790    while(csWritten < csAvail)
     791    {
     792        /* How much is left? */
     793        csToWrite = csAvail - csWritten;
     794        cbToWrite = csToWrite << caVoice->hw.info.shift;
     795        Log2(("CoreAudio: [Input] Try writing %RU32 samples (%RU32 bytes)\n", csToWrite, cbToWrite));
     796        /* Try to aquire the necessary space from the ring buffer. */
     797        IORingBufferAquireWriteBlock(caVoice->pBuf, cbToWrite, &pcDst, &cbToWrite);
     798        /* How much to we get? */
     799        csToWrite = cbToWrite >> caVoice->hw.info.shift;
     800        Log2(("CoreAudio: [Input] There is space for %RU32 samples (%RU32 bytes) available\n", csToWrite, cbToWrite));
     801        /* Break if nothing is free anymore. */
     802        if (RT_UNLIKELY(cbToWrite == 0))
     803            break;
     804        /* Copy the data from the core audio buffer to the ring buffer. */
     805        memcpy(pcDst, (char*)caVoice->pcaBufferList->mBuffers[0].mData + (csWritten << caVoice->hw.info.shift), cbToWrite);
     806        /* Release the ring buffer, so the main thread could start reading this data. */
     807        IORingBufferReleaseWriteBlock(caVoice->pBuf, cbToWrite);
     808        csWritten += csToWrite;
     809    }
     810    /* Cleanup */
     811    RTMemFree(caVoice->pcaBufferList->mBuffers[0].mData);
     812
     813    Log2(("CoreAudio: [Input] Finished writing buffer with %RU32 samples (%RU32 bytes)\n", csWritten, csWritten << caVoice->hw.info.shift));
     814
     815    return noErr;
     816}
     817
     818static int coreaudio_run_in(HWVoiceIn *hw)
     819{
     820    uint32_t csAvail = 0;
     821    uint32_t cbToRead = 0;
     822    uint32_t csToRead = 0;
     823    uint32_t csReads = 0;
     824    char *pcSrc;
     825    st_sample_t *psDst;
     826
     827    caVoiceIn *caVoice = (caVoiceIn *) hw;
     828
     829    /* How much space is used in the ring buffer? */
     830    csAvail = IORingBufferUsed(caVoice->pBuf) >> hw->info.shift; /* bytes -> samples */
     831    /* How much space is available in the mix buffer. Use the smaller size of
     832     * the too. */
     833    csAvail = RT_MIN(csAvail, (uint32_t)(hw->samples - audio_pcm_hw_get_live_in (hw)));
     834
     835    Log2(("CoreAudio: [Input] Start reading buffer with %RU32 samples (%RU32 bytes)\n", csAvail, csAvail << caVoice->hw.info.shift));
     836
     837    /* Iterate as long as data is available */
     838    while (csReads < csAvail)
     839    {
     840        /* How much is left? Split request at the end of our samples buffer. */
     841        csToRead = RT_MIN(csAvail - csReads, (uint32_t)(hw->samples - hw->wpos));
     842        cbToRead = csToRead << hw->info.shift;
     843        Log2(("CoreAudio: [Input] Try reading %RU32 samples (%RU32 bytes)\n", csToRead, cbToRead));
     844        /* Try to aquire the necessary block from the ring buffer. */
     845        IORingBufferAquireReadBlock(caVoice->pBuf, cbToRead, &pcSrc, &cbToRead);
     846        /* How much to we get? */
     847        csToRead = cbToRead >> hw->info.shift;
     848        Log2(("CoreAudio: [Input] There are %RU32 samples (%RU32 bytes) available\n", csToRead, cbToRead));
     849        /* Break if nothing is used anymore. */
     850        if (cbToRead == 0)
     851            break;
     852        /* Copy the data from our ring buffer to the mix buffer. */
     853        psDst = hw->conv_buf + hw->wpos;
     854        hw->conv(psDst, pcSrc, csToRead, &nominal_volume);
     855        /* Release the read buffer, so it could be used for new data. */
     856        IORingBufferReleaseReadBlock(caVoice->pBuf, cbToRead);
     857        hw->wpos = (hw->wpos + csToRead) % hw->samples;
     858        /* How much have we reads so far. */
     859        csReads += csToRead;
     860    }
     861
     862    Log2(("CoreAudio: [Input] Finished reading buffer with %RU32 samples (%RU32 bytes)\n", csReads, csReads << caVoice->hw.info.shift));
     863
     864    return csReads;
     865}
     866
     867static int coreaudio_read(SWVoiceIn *sw, void *buf, int size)
     868{
     869    return audio_pcm_sw_read (sw, buf, size);
     870}
     871
     872static int coreaudio_init_in(HWVoiceIn *hw, audsettings_t *as)
     873{
     874    OSStatus err = noErr;
     875    int rc = -1;
     876    UInt32 uSize = 0; /* temporary size of properties */
     877    UInt32 uFlag = 0; /* for setting flags */
     878    CFStringRef name; /* for the temporary device name fetching */
     879    const char *pszName;
     880    ComponentDescription cd; /* description for an audio component */
     881    Component cp; /* an audio component */
     882    AURenderCallbackStruct cb; /* holds the callback structure */
     883    UInt32 cFrames; /* default frame count */
     884
     885    caVoiceIn *caVoice = (caVoiceIn *) hw;
     886
     887    /* Initialize the hardware info section with the audio settings */
     888    audio_pcm_init_info(&hw->info, as);
     889
     890    /* Fetch the default audio input device currently in use */
     891    uSize = sizeof(caVoice->audioDeviceId);
     892    err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice,
     893                                   &uSize,
     894                                   &caVoice->audioDeviceId);
     895    if (RT_UNLIKELY(err != noErr))
     896    {
     897        LogRel(("CoreAudio: [Input] Unable to find default input device (%RI32)\n", err));
     898        return -1;
     899    }
     900
     901    /* Try to get the name of the default input device and log it. It's not
     902     * fatal if it fails. */
     903    uSize = sizeof(CFStringRef);
     904    err = AudioDeviceGetProperty(caVoice->audioDeviceId,
     905                                 0,
     906                                 1,
     907                                 kAudioObjectPropertyName,
     908                                 &uSize,
     909                                 &name);
     910    if (RT_LIKELY(err == noErr))
     911    {
     912        pszName = CFStringGetCStringPtr(name, kCFStringEncodingMacRoman);
     913        if (pszName)
     914            LogRel(("CoreAudio: Using default input device: %s\n", pszName));
     915        CFRelease(name);
     916    }
     917    else
     918        LogRel(("CoreAudio: [Input] Unable to get input device name (%RI32)\n", err));
     919
     920    cd.componentType = kAudioUnitType_Output;
     921    cd.componentSubType = kAudioUnitSubType_HALOutput;
     922    cd.componentManufacturer = kAudioUnitManufacturer_Apple;
     923    cd.componentFlags = 0;
     924    cd.componentFlagsMask = 0;
     925
     926    /* Try to find the default HAL output component. */
     927    cp = FindNextComponent(NULL, &cd);
     928    if (RT_UNLIKELY(cp == 0))
     929    {
     930        LogRel(("CoreAudio: [Input] Failed to find HAL output component\n"));
     931        return -1;
     932    }
     933
     934    /* Open the default HAL output component. */
     935    err = OpenAComponent(cp, &caVoice->audioUnit);
     936    if (RT_UNLIKELY(err != noErr))
     937    {
     938        LogRel(("CoreAudio: [Input] Failed to open output component (%RI32)\n", err));
     939        return -1;
     940    }
     941
     942    /* Switch the I/O mode for input to on. */
     943    uFlag = 1;
     944    err = AudioUnitSetProperty(caVoice->audioUnit,
     945                               kAudioOutputUnitProperty_EnableIO,
     946                               kAudioUnitScope_Input,
     947                               1,
     948                               &uFlag,
     949                               sizeof(uFlag));
     950    if (RT_UNLIKELY(err != noErr))
     951    {
     952        LogRel(("CoreAudio: [Input] Failed to set input I/O mode enabled (%RI32)\n", err));
     953        return -1;
     954    }
     955
     956    /* Switch the I/O mode for output to off. This is important, as this is a
     957     * pure input stream. */
     958    uFlag = 0;
     959    err = AudioUnitSetProperty(caVoice->audioUnit,
     960                               kAudioOutputUnitProperty_EnableIO,
     961                               kAudioUnitScope_Output,
     962                               0,
     963                               &uFlag,
     964                               sizeof(uFlag));
     965    if (RT_UNLIKELY(err != noErr))
     966    {
     967        LogRel(("CoreAudio: [Input] Failed to set output I/O mode disabled (%RI32)\n", err));
     968        return -1;
     969    }
     970
     971    /* CoreAudio will inform us on a second thread for new incoming audio data.
     972     * Therfor register an callback function, which will process the new data.
     973     * */
     974    cb.inputProc = caRecordingCallback;
     975    cb.inputProcRefCon = caVoice;
     976
     977    err = AudioUnitSetProperty(caVoice->audioUnit,
     978                               kAudioOutputUnitProperty_SetInputCallback,
     979                               kAudioUnitScope_Global,
     980                               0,
     981                               &cb,
     982                               sizeof(cb));
     983    if (RT_UNLIKELY(err != noErr))
     984    {
     985        LogRel(("CoreAudio: [Input] Failed to set callback (%RI32)\n", err));
     986        return -1;
     987    }
     988
     989    /* Set the default audio input device as the device for the new AudioUnit. */
     990    err = AudioUnitSetProperty(caVoice->audioUnit,
     991                               kAudioOutputUnitProperty_CurrentDevice,
     992                               kAudioUnitScope_Global,
     993                               0,
     994                               &caVoice->audioDeviceId,
     995                               sizeof(caVoice->audioDeviceId));
     996    if (RT_UNLIKELY(err != noErr))
     997    {
     998        LogRel(("CoreAudio: [Input] Failed to set current device (%RI32)\n", err));
     999        return -1;
     1000    }
     1001
     1002/*    UInt32 fpb = 1024;*/
     1003/*    if (AudioDeviceSetProperty(core->audioDeviceId,*/
     1004/*                               NULL,*/
     1005/*                               0,*/
     1006/*                               1,*/
     1007/*                               kAudioDevicePropertyBufferSize,*/
     1008/*                               sizeof(fpb), &fpb) != noErr)*/
     1009/*    {*/
     1010/*        LogRel(("CoreAudio: [Input] Unable to set frame buffer size)\n"));*/
     1011/*        return -1;*/
     1012/*    }*/
     1013
     1014    /* Fetch the current stream format of the device. */
     1015    uSize = sizeof(caVoice->deviceFormat);
     1016    err = AudioUnitGetProperty(caVoice->audioUnit,
     1017                               kAudioUnitProperty_StreamFormat,
     1018                               kAudioUnitScope_Input,
     1019                               1,
     1020                               &caVoice->deviceFormat,
     1021                               &uSize);
     1022    if (RT_UNLIKELY(err != noErr))
     1023    {
     1024        LogRel(("CoreAudio: [Input] Failed to get device format (%RI32)\n", err));
     1025        return -1;
     1026    }
     1027
     1028    /* Create an AudioStreamBasicDescription based on the audio settings of
     1029     * VirtualBox. */
     1030    caAudioSettingsToAudioStreamBasicDescription(as, &caVoice->streamFormat);
     1031
     1032#if DEBUG
     1033    caDebugOutputAudioStreamBasicDescription("CoreAudio: [Input] device", &caVoice->deviceFormat);
     1034    caDebugOutputAudioStreamBasicDescription("CoreAudio: [Input] input", &caVoice->streamFormat);
     1035#endif /* DEBUG */
     1036
     1037    /* If the frequency of the device is different from the requested one we
     1038     * need a converter. */
     1039    if (caVoice->deviceFormat.mSampleRate != caVoice->streamFormat.mSampleRate)
     1040    {
     1041        Log(("CoreAudio: [Input] Converter in use\n"));
     1042        /* Set the device format description for the stream. */
     1043        err = AudioUnitSetProperty(caVoice->audioUnit,
     1044                                   kAudioUnitProperty_StreamFormat,
     1045                                   kAudioUnitScope_Output,
     1046                                   1,
     1047                                   &caVoice->deviceFormat,
     1048                                   sizeof(caVoice->deviceFormat));
     1049    }
     1050    else
     1051    {
     1052        /* Set the new format description for the stream. */
     1053        err = AudioUnitSetProperty(caVoice->audioUnit,
     1054                                   kAudioUnitProperty_StreamFormat,
     1055                                   kAudioUnitScope_Output,
     1056                                   1,
     1057                                   &caVoice->streamFormat,
     1058                                   sizeof(caVoice->streamFormat));
     1059    }
     1060    if (RT_UNLIKELY(err != noErr))
     1061    {
     1062        LogRel(("CoreAudio: [Input] Failed to set stream format (%RI32)\n", err));
     1063        return -1;
     1064    }
     1065
     1066    /* Get the default frames per slice size, so that we can setup our internal
     1067     * buffers. */
     1068    uSize = sizeof(cFrames);
     1069    err = AudioUnitGetProperty(caVoice->audioUnit,
     1070                               kAudioDevicePropertyBufferFrameSize,
     1071                               kAudioUnitScope_Global,
     1072                               0,
     1073                               &cFrames,
     1074                               &uSize);
     1075    if (RT_UNLIKELY(err != noErr))
     1076    {
     1077        LogRel(("CoreAudio: [Input] Failed to get maximum frame per slice (%RI32)\n", err));
     1078        return -1;
     1079    }
     1080
     1081    /* Finaly init the new AudioUnit. */
     1082    err = AudioUnitInitialize(caVoice->audioUnit);
     1083    if (RT_UNLIKELY(err != noErr))
     1084    {
     1085        LogRel(("CoreAudio: [Input] Failed to initialize the AudioUnit (%RI32)\n", err));
     1086        return -1;
     1087    }
     1088
     1089    /* Set to zero first */
     1090    caVoice->pcaBufferList = NULL;
     1091    caVoice->pBuf = NULL;
     1092    /* Create the AudioBufferList structure with one buffer. */
     1093    caVoice->pcaBufferList = RTMemAllocZ(sizeof(AudioBufferList) + sizeof(AudioBuffer));
     1094    if (VALID_PTR(caVoice->pcaBufferList))
     1095    {
     1096        caVoice->pcaBufferList->mNumberBuffers = 1;
     1097        /* Initialize the buffer to nothing. */
     1098        caVoice->pcaBufferList->mBuffers[0].mNumberChannels = caVoice->streamFormat.mChannelsPerFrame;
     1099        caVoice->pcaBufferList->mBuffers[0].mDataByteSize = 0;
     1100        caVoice->pcaBufferList->mBuffers[0].mData = NULL;
     1101
     1102        /* Create the internal ring buffer. */
     1103        hw->samples = cFrames * caVoice->streamFormat.mChannelsPerFrame;
     1104        IORingBufferCreate(&caVoice->pBuf, hw->samples << hw->info.shift);
     1105        if (VALID_PTR(caVoice->pBuf))
     1106            rc = 0;
     1107        else
     1108            LogRel(("CoreAudio: [Input] Failed to create internal ring buffer\n"));
     1109    }
     1110    else
     1111        LogRel(("CoreAudio: [Input] Failed to create the audio buffer list\n"));
     1112
     1113    if (rc != 0)
     1114    {
     1115        if (caVoice->pcaBufferList)
     1116            RTMemFree(caVoice->pcaBufferList);
     1117        if (caVoice->pBuf)
     1118            IORingBufferDestroy(caVoice->pBuf);
     1119        AudioUnitUninitialize(caVoice->audioUnit);
     1120    }
     1121
     1122    Log(("CoreAudio: [Input] HW samples: %d; Frame count: %RU32\n", hw->samples, cFrames));
     1123
    2881124    return 0;
    2891125}
    2901126
    291 static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
    292 {
    293     return audio_pcm_sw_write (sw, buf, len);
    294 }
    295 
    296 static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as)
    297 {
    298     OSStatus status;
    299     coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
    300     UInt32 propertySize;
    301     int err;
    302     const char *typ = "playback";
    303     AudioValueRange frameRange;
    304 
    305     /* create mutex */
    306     err = pthread_mutex_init(&core->mutex, NULL);
    307     if (err) {
    308         dolog("Could not create mutex\nReason: %s\n", strerror (err));
    309         return -1;
    310     }
    311 
    312     audio_pcm_init_info (&hw->info, as);
    313 
    314     /* open default output device */
    315     propertySize = sizeof(core->outputDeviceID);
    316     status = AudioHardwareGetProperty(
    317         kAudioHardwarePropertyDefaultOutputDevice,
    318         &propertySize,
    319         &core->outputDeviceID);
    320     if (status != kAudioHardwareNoError) {
    321         coreaudio_logerr2 (status, typ,
    322                            "Could not get default output Device\n");
    323         return -1;
    324     }
    325     if (core->outputDeviceID == kAudioDeviceUnknown) {
    326         dolog ("Could not initialize %s - Unknown Audiodevice\n", typ);
    327         return -1;
    328     }
    329 
    330     /* get minimum and maximum buffer frame sizes */
    331     propertySize = sizeof(frameRange);
    332     status = AudioDeviceGetProperty(
    333         core->outputDeviceID,
    334         0,
    335         0,
    336         kAudioDevicePropertyBufferFrameSizeRange,
    337         &propertySize,
    338         &frameRange);
    339     if (status != kAudioHardwareNoError) {
    340         coreaudio_logerr2 (status, typ,
    341                            "Could not get device buffer frame range\n");
    342         return -1;
    343     }
    344 
    345     if (frameRange.mMinimum > conf.buffer_frames) {
    346         core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
    347         dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
    348     }
    349     else if (frameRange.mMaximum < conf.buffer_frames) {
    350         core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
    351         dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
    352     }
    353     else {
    354         core->audioDevicePropertyBufferFrameSize = conf.buffer_frames;
    355     }
    356 
    357     /* set Buffer Frame Size */
    358     propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
    359     status = AudioDeviceSetProperty(
    360         core->outputDeviceID,
    361         NULL,
    362         0,
    363         false,
    364         kAudioDevicePropertyBufferFrameSize,
    365         propertySize,
    366         &core->audioDevicePropertyBufferFrameSize);
    367     if (status != kAudioHardwareNoError) {
    368         coreaudio_logerr2 (status, typ,
    369                            "Could not set device buffer frame size %ld\n",
    370                            core->audioDevicePropertyBufferFrameSize);
    371         return -1;
    372     }
    373 
    374     /* get Buffer Frame Size */
    375     propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
    376     status = AudioDeviceGetProperty(
    377         core->outputDeviceID,
    378         0,
    379         false,
    380         kAudioDevicePropertyBufferFrameSize,
    381         &propertySize,
    382         &core->audioDevicePropertyBufferFrameSize);
    383     if (status != kAudioHardwareNoError) {
    384         coreaudio_logerr2 (status, typ,
    385                            "Could not get device buffer frame size\n");
    386         return -1;
    387     }
    388     hw->samples = conf.nbuffers * core->audioDevicePropertyBufferFrameSize;
    389 
    390     /* get StreamFormat */
    391     propertySize = sizeof(core->outputStreamBasicDescription);
    392     status = AudioDeviceGetProperty(
    393         core->outputDeviceID,
    394         0,
    395         false,
    396         kAudioDevicePropertyStreamFormat,
    397         &propertySize,
    398         &core->outputStreamBasicDescription);
    399     if (status != kAudioHardwareNoError) {
    400         coreaudio_logerr2 (status, typ,
    401                            "Could not get Device Stream properties\n");
    402         core->outputDeviceID = kAudioDeviceUnknown;
    403         return -1;
    404     }
    405 
    406     /* set Samplerate */
    407     core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
    408     propertySize = sizeof(core->outputStreamBasicDescription);
    409     status = AudioDeviceSetProperty(
    410         core->outputDeviceID,
    411         0,
    412         0,
    413         0,
    414         kAudioDevicePropertyStreamFormat,
    415         propertySize,
    416         &core->outputStreamBasicDescription);
    417     if (status != kAudioHardwareNoError) {
    418         coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n",
    419                            as->freq);
    420         core->outputDeviceID = kAudioDeviceUnknown;
    421         return -1;
    422     }
    423 
    424     /* set Callback */
    425     status = AudioDeviceAddIOProc(core->outputDeviceID, audioDeviceIOProc, hw);
    426     if (status != kAudioHardwareNoError) {
    427         coreaudio_logerr2 (status, typ, "Could not set IOProc\n");
    428         core->outputDeviceID = kAudioDeviceUnknown;
    429         return -1;
    430     }
    431 
    432     /* start Playback */
    433     if (!isPlaying(core->outputDeviceID)) {
    434         status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
    435         if (status != kAudioHardwareNoError) {
    436             coreaudio_logerr2 (status, typ, "Could not start playback\n");
    437             AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc);
    438             core->outputDeviceID = kAudioDeviceUnknown;
    439             return -1;
     1127static void coreaudio_fini_in(HWVoiceIn *hw)
     1128{
     1129    OSStatus err = noErr;
     1130    caVoiceIn *caVoice = (caVoiceIn *) hw;
     1131
     1132    /* Only stop the device if it is actually running */
     1133    if (caIsRunning(caVoice->audioDeviceId))
     1134        err = AudioOutputUnitStop(caVoice->audioUnit);
     1135    if (RT_LIKELY(err == noErr))
     1136    {
     1137        err = AudioUnitUninitialize(caVoice->audioUnit);
     1138        if (RT_LIKELY(err == noErr))
     1139        {
     1140            caVoice->audioDeviceId = kAudioDeviceUnknown;
     1141            IORingBufferDestroy(caVoice->pBuf);
     1142            RTMemFree(caVoice->pcaBufferList);
    4401143        }
    441     }
    442 
     1144        else
     1145            LogRel(("CoreAudio: [Input] Failed to uninitialize the AudioUnit (%RI32)\n", err));
     1146    }
     1147    else
     1148        LogRel(("CoreAudio: [Input] Failed to stop recording (%RI32)\n", err));
     1149}
     1150
     1151static int coreaudio_ctl_in(HWVoiceIn *hw, int cmd, ...)
     1152{
     1153    OSStatus err = noErr;
     1154    caVoiceIn *caVoice = (caVoiceIn *) hw;
     1155
     1156    switch (cmd)
     1157    {
     1158        case VOICE_ENABLE:
     1159            {
     1160                /* Only start the device if it is actually stopped */
     1161                if (!caIsRunning(caVoice->audioDeviceId))
     1162                {
     1163                    IORingBufferReset(caVoice->pBuf);
     1164                    err = AudioOutputUnitStart(caVoice->audioUnit);
     1165                }
     1166                if (RT_UNLIKELY(err != noErr))
     1167                {
     1168                    LogRel(("CoreAudio: [Input] Failed to start recording (%RI32)\n", err));
     1169                    return -1;
     1170                }
     1171                break;
     1172            }
     1173        case VOICE_DISABLE:
     1174            {
     1175                /* Only stop the device if it is actually running */
     1176                if (caIsRunning(caVoice->audioDeviceId))
     1177                    err = AudioOutputUnitStop(caVoice->audioUnit);
     1178                if (RT_UNLIKELY(err != noErr))
     1179                {
     1180                    LogRel(("CoreAudio: [Input] Failed to stop recording (%RI32)\n", err));
     1181                    return -1;
     1182                }
     1183                break;
     1184            }
     1185    }
    4431186    return 0;
    4441187}
    4451188
    446 static void coreaudio_fini_out (HWVoiceOut *hw)
    447 {
    448     OSStatus status;
    449     int err;
    450     coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
    451 
    452     if (!conf.isAtexit) {
    453         /* stop playback */
    454         if (isPlaying(core->outputDeviceID)) {
    455             status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
    456             if (status != kAudioHardwareNoError) {
    457                 coreaudio_logerr (status, "Could not stop playback\n");
    458             }
    459         }
    460 
    461         /* remove callback */
    462         status = AudioDeviceRemoveIOProc(core->outputDeviceID,
    463                                          audioDeviceIOProc);
    464         if (status != kAudioHardwareNoError) {
    465             coreaudio_logerr (status, "Could not remove IOProc\n");
    466         }
    467     }
    468     core->outputDeviceID = kAudioDeviceUnknown;
    469 
    470     /* destroy mutex */
    471     err = pthread_mutex_destroy(&core->mutex);
    472     if (err) {
    473         dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
    474     }
    475 }
    476 
    477 static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
    478 {
    479     OSStatus status;
    480     coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
    481 
    482     switch (cmd) {
    483     case VOICE_ENABLE:
    484         /* start playback */
    485         if (!isPlaying(core->outputDeviceID)) {
    486             status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
    487             if (status != kAudioHardwareNoError) {
    488                 coreaudio_logerr (status, "Could not resume playback\n");
    489             }
    490         }
    491         break;
    492 
    493     case VOICE_DISABLE:
    494         /* stop playback */
    495         if (!conf.isAtexit) {
    496             if (isPlaying(core->outputDeviceID)) {
    497                 status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
    498                 if (status != kAudioHardwareNoError) {
    499                     coreaudio_logerr (status, "Could not pause playback\n");
    500                 }
    501             }
    502         }
    503         break;
    504     }
    505     return 0;
    506 }
    507 
    508 static void *coreaudio_audio_init (void)
    509 {
    510     atexit(coreaudio_atexit);
    511     return &coreaudio_audio_init;
    512 }
    513 
    514 static void coreaudio_audio_fini (void *opaque)
    515 {
    516     (void) opaque;
    517 }
    518 
    519 static struct audio_option coreaudio_options[] = {
    520     {"BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_frames,
     1189/*******************************************************************************
     1190 *
     1191 * CoreAudio global section
     1192 *
     1193 ******************************************************************************/
     1194
     1195static void *coreaudio_audio_init(void)
     1196{
     1197    return &conf;
     1198}
     1199
     1200static void coreaudio_audio_fini(void *opaque)
     1201{
     1202    NOREF(opaque);
     1203}
     1204
     1205static struct audio_option coreaudio_options[] =
     1206{
     1207    {"BUFFER_SIZE", AUD_OPT_INT, &conf.cBufferFrames,
    5211208     "Size of the buffer in frames", NULL, 0},
    522     {"BUFFER_COUNT", AUD_OPT_INT, &conf.nbuffers,
    523      "Number of buffers", NULL, 0},
    5241209    {NULL, 0, NULL, NULL, NULL, 0}
    5251210};
    5261211
    527 static struct audio_pcm_ops coreaudio_pcm_ops = {
     1212static struct audio_pcm_ops coreaudio_pcm_ops =
     1213{
    5281214    coreaudio_init_out,
    5291215    coreaudio_fini_out,
     
    5321218    coreaudio_ctl_out,
    5331219
    534     NULL,
    535     NULL,
    536     NULL,
    537     NULL,
    538     NULL
     1220    coreaudio_init_in,
     1221    coreaudio_fini_in,
     1222    coreaudio_run_in,
     1223    coreaudio_read,
     1224    coreaudio_ctl_in
    5391225};
    5401226
    541 struct audio_driver coreaudio_audio_driver = {
    542     INIT_FIELD (name           = ) "coreaudio",
    543     INIT_FIELD (descr          = )
     1227struct audio_driver coreaudio_audio_driver =
     1228{
     1229    INIT_FIELD(name           =) "coreaudio",
     1230    INIT_FIELD(descr          =)
    5441231    "CoreAudio http://developer.apple.com/audio/coreaudio.html",
    545     INIT_FIELD (options        = ) coreaudio_options,
    546     INIT_FIELD (init           = ) coreaudio_audio_init,
    547     INIT_FIELD (fini           = ) coreaudio_audio_fini,
    548     INIT_FIELD (pcm_ops        = ) &coreaudio_pcm_ops,
    549     INIT_FIELD (can_be_default = ) 1,
    550     INIT_FIELD (max_voices_out = ) 1,
    551     INIT_FIELD (max_voices_in  = ) 0,
    552     INIT_FIELD (voice_size_out = ) sizeof (coreaudioVoiceOut),
    553     INIT_FIELD (voice_size_in  = ) 0
     1232    INIT_FIELD(options        =) coreaudio_options,
     1233    INIT_FIELD(init           =) coreaudio_audio_init,
     1234    INIT_FIELD(fini           =) coreaudio_audio_fini,
     1235    INIT_FIELD(pcm_ops        =) &coreaudio_pcm_ops,
     1236    INIT_FIELD(can_be_default =) 1,
     1237    INIT_FIELD(max_voices_out =) 1,
     1238    INIT_FIELD(max_voices_in  =) 1,
     1239    INIT_FIELD(voice_size_out =) sizeof(caVoiceOut),
     1240    INIT_FIELD(voice_size_in  =) sizeof(caVoiceIn)
    5541241};
     1242
  • trunk/src/VBox/Devices/Makefile.kmk

    r25336 r25770  
    231231VBoxDD_LDFLAGS.darwin   = -install_name $(VBOX_DYLD_EXECUTABLE_PATH)/VBoxDD.dylib \
    232232        -framework CoreAudio \
     233        -framework AudioUnit \
    233234        -framework IOKit \
    234235        -framework Carbon \
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette