bool PlexAudioDevice::computeStreamSupportsDigital(AudioStreamID streamID) { bool ret = false; OSStatus err = noErr; UInt32 paramSize = 0; // Retrieve all the stream formats supported by each output stream. SAFELY(AudioStreamGetPropertyInfo(streamID, 0, kAudioStreamPropertyPhysicalFormats, ¶mSize, NULL)); if (err == noErr) { int numFormats = paramSize / sizeof(AudioStreamBasicDescription); AudioStreamBasicDescription* pFormatList = (AudioStreamBasicDescription *)malloc(paramSize); SAFELY(AudioStreamGetProperty(streamID, 0, kAudioStreamPropertyPhysicalFormats, ¶mSize, pFormatList)); if (err == noErr) { for(int i=0; i<numFormats && ret == false; i++) { if (pFormatList[i].mFormatID == 'IAC3' || pFormatList[i].mFormatID == kAudioFormat60958AC3) ret = true; } } free(pFormatList); } return ret; }
bool CCoreAudioStream::GetPhysicalFormat(AudioStreamID id, AudioStreamBasicDescription* pDesc) { if (!pDesc || !id) return false; UInt32 size = sizeof(AudioStreamBasicDescription); OSStatus ret = AudioStreamGetProperty(id, 0, kAudioStreamPropertyPhysicalFormat, &size, pDesc); if (ret) return false; return true; }
UInt32 CCoreAudioStream::GetLatency(AudioStreamID id) { if (!id) return 0; UInt32 size = sizeof(UInt32); UInt32 val = 0; OSStatus ret = AudioStreamGetProperty(id, 0, kAudioStreamPropertyLatency, &size, &val); if (ret) return 0; return val; }
UInt32 CCoreAudioStream::GetTerminalType() { if (!m_StreamId) return 0; UInt32 size = sizeof(UInt32); UInt32 val = 0; OSStatus ret = AudioStreamGetProperty(m_StreamId, 0, kAudioStreamPropertyTerminalType, &size, &val); if (ret) return 0; return val; }
UInt32 CCoreAudioStream::GetDirection() { if (!m_StreamId) return 0; UInt32 size = sizeof(UInt32); UInt32 val = 0; OSStatus ret = AudioStreamGetProperty(m_StreamId, 0, kAudioStreamPropertyDirection, &size, &val); if (ret) return 0; return val; }
QAudioFormat QAudioDeviceInfoInternal::preferredFormat() const { QAudioFormat rc; UInt32 propSize = 0; if (AudioDeviceGetPropertyInfo(deviceId, 0, mode == QAudio::AudioInput, kAudioDevicePropertyStreams, &propSize, 0) == noErr) { const int sc = propSize / sizeof(AudioStreamID); if (sc > 0) { AudioStreamID* streams = new AudioStreamID[sc]; if (AudioDeviceGetProperty(deviceId, 0, mode == QAudio::AudioInput, kAudioDevicePropertyStreams, &propSize, streams) == noErr) { for (int i = 0; i < sc; ++i) { if (AudioStreamGetPropertyInfo(streams[i], 0, kAudioStreamPropertyPhysicalFormat, &propSize, 0) == noErr) { AudioStreamBasicDescription sf; if (AudioStreamGetProperty(streams[i], 0, kAudioStreamPropertyPhysicalFormat, &propSize, &sf) == noErr) { rc = toQAudioFormat(sf); break; } } } } delete streams; } } return rc; }
UInt32 CCoreAudioStream::GetNumLatencyFrames() { if (!m_StreamId) return 0; UInt32 i_param_size = sizeof(uint32_t); UInt32 i_param, num_latency_frames = 0; // number of frames of latency in the AudioStream if (noErr == AudioStreamGetProperty(m_StreamId, 0, kAudioStreamPropertyLatency, &i_param_size, &i_param)) { num_latency_frames += i_param; } return (num_latency_frames); }
/***************************************************************************** * AudioStreamChangeFormat: Change i_stream_id to change_format *****************************************************************************/ int CoreAudioAUHAL::AudioStreamChangeFormat(CoreAudioDeviceParameters *deviceParameters, AudioStreamID i_stream_id, AudioStreamBasicDescription change_format) { OSStatus err = noErr; UInt32 i_param_size = 0; int i; CLog::Log(LOGINFO, STREAM_FORMAT_MSG( "setting stream format: ", change_format )); CSingleLock lock(m_cs); // acquire lock /* change the format */ err = AudioStreamSetProperty( i_stream_id, 0, 0, kAudioStreamPropertyPhysicalFormat, sizeof( AudioStreamBasicDescription ), &change_format ); if( err != noErr ) { CLog::Log(LOGERROR, "could not set the stream format: [%4.4s]", (char *)&err ); return false; } /* The AudioStreamSetProperty is not only asynchronious (requiring the locks) * it is also not atomic in its behaviour. * Therefore we check 5 times before we really give up.*/ for( i = 0; i < 5; i++ ) { AudioStreamBasicDescription actual_format; usleep(20); i_param_size = sizeof( AudioStreamBasicDescription ); err = AudioStreamGetProperty( i_stream_id, 0, kAudioStreamPropertyPhysicalFormat, &i_param_size, &actual_format ); CLog::Log(LOGDEBUG, STREAM_FORMAT_MSG( "actual format in use: ", actual_format ) ); if( actual_format.mSampleRate == change_format.mSampleRate && actual_format.mFormatID == change_format.mFormatID && actual_format.mFramesPerPacket == change_format.mFramesPerPacket ) { /* The right format is now active */ break; } /* We need to check again */ } return true; }
OSStatus get_total_channels(AudioDeviceID device, int* channelCount, bool isInput) { OSStatus err = noErr; UInt32 outSize; Boolean outWritable; AudioBufferList* bufferList = 0; AudioStreamID* streamList = 0; int i, numStream; err = AudioDeviceGetPropertyInfo(device, 0, isInput, kAudioDevicePropertyStreams, &outSize, &outWritable); if (err == noErr) { streamList = (AudioStreamID*)malloc(outSize); numStream = outSize/sizeof(AudioStreamID); JCALog("get_total_channels device stream number = %ld numStream = %ld\n", device, numStream); err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreams, &outSize, streamList); if (err == noErr) { AudioStreamBasicDescription streamDesc; outSize = sizeof(AudioStreamBasicDescription); for (i = 0; i < numStream; i++) { err = AudioStreamGetProperty(streamList[i], 0, kAudioDevicePropertyStreamFormat, &outSize, &streamDesc); JCALog("get_total_channels streamDesc mFormatFlags = %ld mChannelsPerFrame = %ld\n", streamDesc.mFormatFlags, streamDesc.mChannelsPerFrame); } } } *channelCount = 0; err = AudioDeviceGetPropertyInfo(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, &outWritable); if (err == noErr) { bufferList = (AudioBufferList*)malloc(outSize); err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, bufferList); if (err == noErr) { for (i = 0; i < bufferList->mNumberBuffers; i++) *channelCount += bufferList->mBuffers[i].mNumberChannels; } } if (streamList) free(streamList); if (bufferList) free(bufferList); return err; }
bool CCoreAudioStream::GetAvailablePhysicalFormats(AudioStreamID id, StreamFormatList* pList) { if (!pList || !id) return false; UInt32 propertySize = 0; Boolean writable = false; OSStatus ret = AudioStreamGetPropertyInfo(id, 0, kAudioStreamPropertyAvailablePhysicalFormats, &propertySize, &writable); if (ret) return false; UInt32 formatCount = propertySize / sizeof(AudioStreamRangedDescription); AudioStreamRangedDescription* pFormatList = new AudioStreamRangedDescription[formatCount]; ret = AudioStreamGetProperty(id, 0, kAudioStreamPropertyAvailablePhysicalFormats, &propertySize, pFormatList); if (!ret) { for (UInt32 format = 0; format < formatCount; format++) pList->push_back(pFormatList[format]); } delete[] pFormatList; return (ret == noErr); }
AudioStreamBasicDescription* CCoreAudioHardware::FormatsList(AudioStreamID stream) { // This is deprecated for kAudioStreamPropertyAvailablePhysicalFormats, // but compiling on 10.3 requires the older constant AudioDevicePropertyID p = kAudioStreamPropertyPhysicalFormats; UInt32 listSize; // Retrieve all the stream formats supported by this output stream OSStatus ret = AudioStreamGetPropertyInfo(stream, 0, p, &listSize, NULL); if (ret != noErr) { CLog::Log(LOGDEBUG, "CCoreAudioHardware::FormatsList: " "Unable to get list size. Error = %s", GetError(ret).c_str()); return NULL; } // Space for a terminating ID: listSize += sizeof(AudioStreamBasicDescription); AudioStreamBasicDescription *list = (AudioStreamBasicDescription*)malloc(listSize); if (list == NULL) { CLog::Log(LOGERROR, "CCoreAudioHardware::FormatsList: Out of memory?"); return NULL; } ret = AudioStreamGetProperty(stream, 0, p, &listSize, list); if (ret != noErr) { CLog::Log(LOGDEBUG, "CCoreAudioHardware::FormatsList: " "Unable to get list. Error = %s", GetError(ret).c_str()); free(list); return NULL; } // Add a terminating ID: list[listSize/sizeof(AudioStreamID)].mFormatID = 0; return list; }
void CCoreAudioHardware::ResetStream(AudioStreamID stream) { // Find the streams current physical format AudioStreamBasicDescription currentFormat; UInt32 paramSize = sizeof(currentFormat); AudioStreamGetProperty(stream, 0, kAudioStreamPropertyPhysicalFormat, ¶mSize, ¤tFormat); // If it's currently AC-3/SPDIF then reset it to some mixable format if (currentFormat.mFormatID == 'IAC3' || currentFormat.mFormatID == kAudioFormat60958AC3) { AudioStreamBasicDescription *formats = CCoreAudioHardware::FormatsList(stream); bool streamReset = false; if (!formats) return; for (int i = 0; !streamReset && formats[i].mFormatID != 0; i++) { if (formats[i].mFormatID == kAudioFormatLinearPCM) { OSStatus ret = AudioStreamSetProperty(stream, NULL, 0, kAudioStreamPropertyPhysicalFormat, sizeof(formats[i]), &(formats[i])); if (ret != noErr) { CLog::Log(LOGDEBUG, "CCoreAudioHardware::ResetStream: " "Unable to retrieve the list of available devices. Error = %s", GetError(ret).c_str()); continue; } else { streamReset = true; Sleep(10); } } } free(formats); } }
void CAPlayThroughHost::RemoveDeviceListeners(AudioDeviceID input) { UInt32 propSize; OSStatus err = AudioDeviceGetPropertyInfo(input, 0, true, kAudioDevicePropertyStreams, &propSize, NULL); if(!err) { AudioStreamID *streams = (AudioStreamID*)malloc(propSize); err = AudioDeviceGetProperty(input, 0, true, kAudioDevicePropertyStreams, &propSize, streams); if(!err) { UInt32 numStreams = propSize / sizeof(AudioStreamID); for(UInt32 i=0; i < numStreams; i++) { UInt32 isInput; propSize = sizeof(UInt32); err = AudioStreamGetProperty(streams[i], 0, kAudioStreamPropertyDirection, &propSize, &isInput); if(!err && isInput) err = AudioStreamRemovePropertyListener(streams[i], 0, kAudioStreamPropertyPhysicalFormat, StreamListener); } } } }
void CAPlayThroughHost::AddDeviceListeners(AudioDeviceID input) { // StreamListener is called whenever the sample rate changes (as well as other format characteristics of the device) UInt32 propSize; OSStatus err = AudioDeviceGetPropertyInfo(input, 0, true, kAudioDevicePropertyStreams, &propSize, NULL); if(!err) { AudioStreamID *streams = (AudioStreamID*)malloc(propSize); err = AudioDeviceGetProperty(input, 0, true, kAudioDevicePropertyStreams, &propSize, streams); if(!err); { UInt32 numStreams = propSize / sizeof(AudioStreamID); for(UInt32 i=0; i < numStreams; i++) { UInt32 isInput; propSize = sizeof(UInt32); err = AudioStreamGetProperty(streams[i], 0, kAudioStreamPropertyDirection, &propSize, &isInput); if(!err && isInput); err = AudioStreamAddPropertyListener(streams[i], 0, kAudioStreamPropertyPhysicalFormat, StreamListener, this); } } } }
void CAAudioHardwareStream::GetPropertyData(UInt32 inChannel, AudioHardwarePropertyID inPropertyID, UInt32& ioDataSize, void* outData) const { OSStatus theError = AudioStreamGetProperty(GetAudioStreamID(), inChannel, inPropertyID, &ioDataSize, outData); ThrowIfError(theError, CAException(theError), "CAAudioHardwareStream::GetPropertyData: got an error getting the value of a property"); }
/***************************************************************************** * Setup a encoded digital stream (SPDIF) *****************************************************************************/ int CoreAudioAUHAL::OpenSPDIF(struct CoreAudioDeviceParameters *deviceParameters, const CStdString& strName, int channels, float sampleRate, int bitsPerSample, int packetSize) { OSStatus err = noErr; UInt32 i_param_size = 0, b_mix = 0; Boolean b_writeable = false; AudioStreamID *p_streams = NULL; int i = 0, i_streams = 0; // We're digital. s_lastPlayWasSpdif = true; /* Start doing the SPDIF setup proces */ //deviceParameters->b_digital = true; deviceParameters->b_changed_mixing = false; /* Hog the device */ i_param_size = sizeof(deviceParameters->i_hog_pid); deviceParameters->i_hog_pid = getpid(); err = AudioDeviceSetProperty(deviceParameters->device_id, 0, 0, FALSE, kAudioDevicePropertyHogMode, i_param_size, &deviceParameters->i_hog_pid); if( err != noErr ) { CLog::Log(LOGERROR, "Failed to set hogmode: [%4.4s]", (char *)&err ); return false; } /* Set mixable to false if we are allowed to */ err = AudioDeviceGetPropertyInfo(deviceParameters->device_id, 0, FALSE, kAudioDevicePropertySupportsMixing, &i_param_size, &b_writeable ); err = AudioDeviceGetProperty(deviceParameters->device_id, 0, FALSE, kAudioDevicePropertySupportsMixing, &i_param_size, &b_mix ); if( !err && b_writeable ) { b_mix = 0; err = AudioDeviceSetProperty( deviceParameters->device_id, 0, 0, FALSE, kAudioDevicePropertySupportsMixing, i_param_size, &b_mix ); deviceParameters->b_changed_mixing = true; } if( err != noErr ) { CLog::Log(LOGERROR, "Failed to set mixmode: [%4.4s]", (char *)&err ); return false; } /* Get a list of all the streams on this device */ err = AudioDeviceGetPropertyInfo(deviceParameters->device_id, 0, FALSE, kAudioDevicePropertyStreams, &i_param_size, NULL ); if( err != noErr ) { CLog::Log(LOGERROR, "Could not get number of streams: [%4.4s]", (char *)&err ); return false; } i_streams = i_param_size / sizeof( AudioStreamID ); p_streams = (AudioStreamID *)malloc( i_param_size ); if( p_streams == NULL ) return false; err = AudioDeviceGetProperty(deviceParameters->device_id, 0, FALSE, kAudioDevicePropertyStreams, &i_param_size, p_streams ); if( err != noErr ) { CLog::Log(LOGERROR, "Could not get number of streams: [%4.4s]", (char *)&err ); free( p_streams ); return false; } for( i = 0; i < i_streams && deviceParameters->i_stream_index < 0 ; i++ ) { /* Find a stream with a cac3 stream */ AudioStreamBasicDescription *p_format_list = NULL; int i_formats = 0, j = 0; bool b_digital = false; /* Retrieve all the stream formats supported by each output stream */ err = AudioStreamGetPropertyInfo( p_streams[i], 0, kAudioStreamPropertyPhysicalFormats, &i_param_size, NULL ); if( err != noErr ) { CLog::Log(LOGERROR, "Could not get number of streamformats: [%4.4s]", (char *)&err ); continue; } i_formats = i_param_size / sizeof( AudioStreamBasicDescription ); p_format_list = (AudioStreamBasicDescription *)malloc( i_param_size ); if( p_format_list == NULL ) continue; err = AudioStreamGetProperty( p_streams[i], 0, kAudioStreamPropertyPhysicalFormats, &i_param_size, p_format_list ); if( err != noErr ) { CLog::Log(LOGERROR, "Could not get the list of streamformats: [%4.4s]", (char *)&err ); free( p_format_list ); continue; } /* Check if one of the supported formats is a digital format */ for( j = 0; j < i_formats; j++ ) { if( p_format_list[j].mFormatID == 'IAC3' || p_format_list[j].mFormatID == kAudioFormat60958AC3 ) { b_digital = true; break; } } if( b_digital ) { /* if this stream supports a digital (cac3) format, then go set it. */ int i_requested_rate_format = -1; int i_current_rate_format = -1; int i_backup_rate_format = -1; deviceParameters->i_stream_id = p_streams[i]; deviceParameters->i_stream_index = i; if(deviceParameters->b_revert == false ) { /* Retrieve the original format of this stream first if not done so already */ i_param_size = sizeof(deviceParameters->sfmt_revert); err = AudioStreamGetProperty(deviceParameters->i_stream_id, 0, kAudioStreamPropertyPhysicalFormat, &i_param_size, &deviceParameters->sfmt_revert ); if( err != noErr ) { CLog::Log(LOGERROR, "Could not retrieve the original streamformat: [%4.4s]", (char *)&err ); //continue; } else deviceParameters->b_revert = true; } for( j = 0; j < i_formats; j++ ) { if( p_format_list[j].mFormatID == 'IAC3' || p_format_list[j].mFormatID == kAudioFormat60958AC3 ) { if( p_format_list[j].mSampleRate == sampleRate) { i_requested_rate_format = j; break; } else if( p_format_list[j].mSampleRate == deviceParameters->sfmt_revert.mSampleRate ) { i_current_rate_format = j; } else { if( i_backup_rate_format < 0 || p_format_list[j].mSampleRate > p_format_list[i_backup_rate_format].mSampleRate ) i_backup_rate_format = j; } } } if( i_requested_rate_format >= 0 ) /* We prefer to output at the samplerate of the original audio */ deviceParameters->stream_format = p_format_list[i_requested_rate_format]; else if( i_current_rate_format >= 0 ) /* If not possible, we will try to use the current samplerate of the device */ deviceParameters->stream_format = p_format_list[i_current_rate_format]; else deviceParameters->stream_format = p_format_list[i_backup_rate_format]; /* And if we have to, any digital format will be just fine (highest rate possible) */ } free( p_format_list ); } free( p_streams ); CLog::Log(LOGINFO, STREAM_FORMAT_MSG("original stream format: ", deviceParameters->sfmt_revert ) ); if( !AudioStreamChangeFormat(deviceParameters, deviceParameters->i_stream_id, deviceParameters->stream_format)) return false; // Get device hardware buffer size uint32_t audioDeviceLatency, audioStreamLatency, audioDeviceBufferFrameSize, audioDeviceSafetyOffset; deviceParameters->hardwareFrameLatency = 0; i_param_size = sizeof(uint32_t); err = AudioDeviceGetProperty(deviceParameters->device_id, 0, false, kAudioDevicePropertyLatency, &i_param_size, &audioDeviceLatency); if (err == noErr) deviceParameters->hardwareFrameLatency += audioDeviceLatency; err = AudioDeviceGetProperty(deviceParameters->device_id, 0, false, kAudioDevicePropertyBufferFrameSize, &i_param_size, &audioDeviceBufferFrameSize); if (err == noErr) deviceParameters->hardwareFrameLatency += audioDeviceBufferFrameSize; err = AudioDeviceGetProperty(deviceParameters->device_id, 0, false, kAudioDevicePropertySafetyOffset, &i_param_size, &audioDeviceSafetyOffset); if (err == noErr) deviceParameters->hardwareFrameLatency += audioDeviceSafetyOffset; err = AudioStreamGetProperty(deviceParameters->i_stream_id, 0, kAudioStreamPropertyLatency, &i_param_size, &audioStreamLatency); if (err == noErr) deviceParameters->hardwareFrameLatency += audioStreamLatency; CLog::Log(LOGINFO, "Hardware latency: %i frames (%.2f msec @ %.0fHz)", deviceParameters->hardwareFrameLatency, (float)deviceParameters->hardwareFrameLatency / deviceParameters->stream_format.mSampleRate * 1000, deviceParameters->stream_format.mSampleRate); // initialise the CoreAudio sink buffer uint32_t framecount = 1; while(framecount <= deviceParameters->stream_format.mSampleRate) // ensure power of 2 { framecount <<= 1; } #warning free deviceParameters->outputBuffer = (PaUtilRingBuffer *)malloc(sizeof(PaUtilRingBuffer)); deviceParameters->outputBufferData = calloc(1, framecount * channels * bitsPerSample/8); // use uncompressed size if encoding ac3 PaUtil_InitializeRingBuffer(deviceParameters->outputBuffer, channels * bitsPerSample/8, framecount, deviceParameters->outputBufferData); /* Add IOProc callback */ err = AudioDeviceCreateIOProcID(deviceParameters->device_id, (AudioDeviceIOProc)RenderCallbackSPDIF, deviceParameters, &deviceParameters->sInputIOProcID); if( err != noErr ) { CLog::Log(LOGERROR, "AudioDeviceAddIOProcID failed: [%4.4s]", (char *)&err ); return false; } /* Start device */ err = AudioDeviceStart(deviceParameters->device_id, (AudioDeviceIOProc)RenderCallbackSPDIF ); if( err != noErr ) { CLog::Log(LOGERROR, "AudioDeviceStart failed: [%4.4s]", (char *)&err ); err = AudioDeviceDestroyIOProcID(deviceParameters->device_id, (AudioDeviceIOProc)RenderCallbackSPDIF); if( err != noErr ) { CLog::Log(LOGERROR, "AudioDeviceRemoveIOProc failed: [%4.4s]", (char *)&err ); } return false; } return true; }
static void gviHardwareGetChannelName(GVDevice device, GVDeviceType type, int index, gsi_char name[GV_CHANNEL_NAME_LEN]) { OSStatus result; UInt32 size; CFStringRef nameRef; AudioStreamID * streamIDs; int num; // clear the name in case we abort name[0] = '\0'; // figure out how many channels there are num = gviHardwareGetNumChannels(device, type); // make sure the index we have is valid if((index < 0) || (index >= num)) return; // allocate memory for the stream IDs size = (num * sizeof(AudioStreamID)); streamIDs = (AudioStreamID*)gsimalloc(size); // get the stream IDs result = AudioDeviceGetProperty(device->m_deviceID, 0, (type & GV_CAPTURE)?true:false, kAudioDevicePropertyStreams, &size, streamIDs); if(result == noErr) { // get the CFString for this stream size = sizeof(CFStringRef); result = AudioStreamGetProperty(streamIDs[index], 0, kAudioDevicePropertyDeviceNameCFString, &size, &nameRef); if(result != noErr) nameRef = NULL; } // if there's a blank name, we'll supply our own if(nameRef && (CFStringGetLength(nameRef) <= 0)) { CFRelease(nameRef); nameRef = NULL; } // if there's no name, give a default if(nameRef == NULL) { CFStringRef format; if(type & GV_CAPTURE) format = CFSTR("Input Channel %d"); else format = CFSTR("Output Channel %d"); nameRef = CFStringCreateWithFormat(NULL, NULL, format, index); CFRelease(format); } // convert it to an array of gsi_char gviCFStringToString(nameRef, name, GV_CHANNEL_NAME_LEN); // release the CFString CFRelease(nameRef); // free the streamIDs gsifree(streamIDs); }