void CCoreAudioHardware::ResetStream(AudioStreamID streamId) { CCoreAudioStream stream; stream.Open(streamId); AudioStreamBasicDescription desc; if (stream.GetPhysicalFormat(&desc)) { if (desc.mFormatID == 'IAC3' || desc.mFormatID == kAudioFormat60958AC3) { CLog::Log(LOGDEBUG, "CCoreAudioHardware::ResetStream stream 0x%x is in encoded format.. setting to LPCM", (unsigned int)streamId); StreamFormatList availableFormats; if (stream.GetAvailablePhysicalFormats(&availableFormats)) { for (StreamFormatList::iterator fmtIt = availableFormats.begin(); fmtIt != availableFormats.end() ; ++fmtIt) { AudioStreamRangedDescription fmtDesc = *fmtIt; if (fmtDesc.mFormat.mFormatID == kAudioFormatLinearPCM) { AudioStreamBasicDescription newFmt = fmtDesc.mFormat; if (stream.SetPhysicalFormat(&newFmt)) break; } } } } } stream.Close(false); }
bool CCoreAudioAEHALOSX::InitializeEncoded(AudioDeviceID outputDevice, AEAudioFormat &format) { std::string formatString; AudioStreamID outputStream = 0; AudioStreamBasicDescription outputFormat = {0}; // Fetch a list of the streams defined by the output device UInt32 streamIndex = 0; AudioStreamIdList streams; m_AudioDevice->GetStreams(&streams); m_OutputBufferIndex = 0; while (!streams.empty()) { // Get the next stream CCoreAudioStream stream; stream.Open(streams.front()); streams.pop_front(); // We copied it, now we are done with it // Probe physical formats StreamFormatList physicalFormats; stream.GetAvailablePhysicalFormats(&physicalFormats); while (!physicalFormats.empty()) { AudioStreamRangedDescription& desc = physicalFormats.front(); CLog::Log(LOGDEBUG, "CCoreAudioAEHALOSX::InitializeEncoded: " "Considering Physical Format: %s", StreamDescriptionToString(desc.mFormat, formatString)); if (m_rawDataFormat == AE_FMT_LPCM || m_rawDataFormat == AE_FMT_DTSHD || m_rawDataFormat == AE_FMT_TRUEHD || m_rawDataFormat == AE_FMT_EAC3) { // check pcm output formats unsigned int bps = CAEUtil::DataFormatToBits(AE_FMT_S16NE); if (desc.mFormat.mChannelsPerFrame == m_initformat.m_channelLayout.Count() && desc.mFormat.mBitsPerChannel == bps && desc.mFormat.mSampleRate == m_initformat.m_sampleRate ) { outputFormat = desc.mFormat; // Select this format m_OutputBufferIndex = streamIndex; outputStream = stream.GetId(); break; } } else { // check encoded formats if (desc.mFormat.mFormatID == kAudioFormat60958AC3 || desc.mFormat.mFormatID == 'IAC3') { if (desc.mFormat.mChannelsPerFrame == m_initformat.m_channelLayout.Count() && desc.mFormat.mSampleRate == m_initformat.m_sampleRate ) { outputFormat = desc.mFormat; // Select this format m_OutputBufferIndex = streamIndex; outputStream = stream.GetId(); break; } } } physicalFormats.pop_front(); } // TODO: How do we determine if this is the right stream (not just the right format) to use? if (outputFormat.mFormatID) break; // We found a suitable format. No need to continue. streamIndex++; } if (!outputFormat.mFormatID) // No match found { CLog::Log(LOGDEBUG, "CCoreAudioAEHALOSX::InitializeEncoded: " "Unable to identify suitable output format."); return false; } CLog::Log(LOGDEBUG, "CCoreAudioAEHALOSX::InitializeEncoded: " "Selected stream[%u] - id: 0x%04X, Physical Format: %s", m_OutputBufferIndex, (uint)outputStream, StreamDescriptionToString(outputFormat, formatString)); // TODO: Auto hogging sets this for us. Figure out how/when to turn it off or use it // It appears that leaving this set will aslo restore the previous stream format when the // Application exits. If auto hogging is set and we try to set hog mode, we will deadlock // From the SDK docs: "If the AudioDevice is in a non-mixable mode, the HAL will automatically take hog mode on behalf of the first process to start an IOProc." // Lock down the device. This MUST be done PRIOR to switching to a non-mixable format, if it is done at all // If it is attempted after the format change, there is a high likelihood of a deadlock // We may need to do this sooner to enable mix-disable (i.e. before setting the stream format) // Auto-Hog does not always un-hog the device when changing back to a mixable mode. // Handle this on our own until it is fixed. CCoreAudioHardware::SetAutoHogMode(false); bool autoHog = CCoreAudioHardware::GetAutoHogMode(); CLog::Log(LOGDEBUG, " CoreAudioRenderer::InitializeEncoded: " "Auto 'hog' mode is set to '%s'.", autoHog ? "On" : "Off"); if (!autoHog) // Try to handle this ourselves { // Hog the device if it is not set to be done automatically m_AudioDevice->SetHogStatus(true); // Try to disable mixing. If we cannot, it may not be a problem m_AudioDevice->SetMixingSupport(false); } m_NumLatencyFrames = m_AudioDevice->GetNumLatencyFrames(); // Configure the output stream object, this is the one we will keep m_OutputStream->Open(outputStream); AudioStreamBasicDescription virtualFormat; m_OutputStream->GetVirtualFormat(&virtualFormat); CLog::Log(LOGDEBUG, "CCoreAudioAEHALOSX::InitializeEncoded: " "Previous Virtual Format: %s", StreamDescriptionToString(virtualFormat, formatString)); AudioStreamBasicDescription previousPhysicalFormat; m_OutputStream->GetPhysicalFormat(&previousPhysicalFormat); CLog::Log(LOGDEBUG, "CCoreAudioAEHALOSX::InitializeEncoded: " "Previous Physical Format: %s", StreamDescriptionToString(previousPhysicalFormat, formatString)); // Set the active format (the old one will be reverted when we close) m_OutputStream->SetPhysicalFormat(&outputFormat); m_NumLatencyFrames += m_OutputStream->GetNumLatencyFrames(); m_OutputStream->GetVirtualFormat(&virtualFormat); CLog::Log(LOGDEBUG, "CCoreAudioAEHALOSX::InitializeEncoded: " "New Virtual Format: %s", StreamDescriptionToString(virtualFormat, formatString)); CLog::Log(LOGDEBUG, "CCoreAudioAEHALOSX::InitializeEncoded: " "New Physical Format: %s", StreamDescriptionToString(outputFormat, formatString)); m_allowMixing = false; return true; }