static bool Audio_openAndStart(Audio *audio, const char *alias, char *file) { UInt32 size; OSStatus err1; OSErr err2; ComponentResult err3; char *buff; FSRef path; AudioStreamBasicDescription format; ComponentDescription findComp; Component comp; AURenderCallbackStruct input; buff = MMDAgent_pathdup(file); /* convert file name */ err1 = FSPathMakeRef ((const UInt8 *) buff, &path, NULL); free(buff); if(err1) { return false; } /* open audio file */ err1 = ExtAudioFileOpen(&path, &audio->file); if(err1) { return false; } /* get audio file format */ size = sizeof(AudioStreamBasicDescription); err1 = ExtAudioFileGetProperty(audio->file, kExtAudioFileProperty_FileDataFormat, &size, &format); if(err1) { ExtAudioFileDispose(audio->file); return false; } /* convert audio format to pcm (32bit stereo with the same sampling rate) */ format.mSampleRate = format.mSampleRate; format.mFormatID = kAudioFormatLinearPCM; format.mFormatFlags = kAudioFormatFlagsNativeFloatPacked; format.mBytesPerPacket = 4 * 2; format.mFramesPerPacket = 1; format.mBytesPerFrame = 4 * 2; format.mChannelsPerFrame = 2; format.mBitsPerChannel = 32; format.mReserved = format.mReserved; size = sizeof(AudioStreamBasicDescription); err1 = ExtAudioFileSetProperty(audio->file, kExtAudioFileProperty_ClientDataFormat, size, &format); if(err1) { ExtAudioFileDispose(audio->file); return false; } /* open audio device */ findComp.componentType = kAudioUnitType_Output; findComp.componentSubType = kAudioUnitSubType_DefaultOutput; findComp.componentManufacturer = kAudioUnitManufacturer_Apple; findComp.componentFlags = 0; findComp.componentFlagsMask = 0; comp = FindNextComponent(NULL, &findComp); if(comp == 0) { ExtAudioFileDispose(audio->file); return false; } err2 = OpenAComponent(comp, &audio->device); if(err2) { ExtAudioFileDispose(audio->file); return false; } /* set callback func. */ input.inputProc = renderCallback; input.inputProcRefCon = audio; size = sizeof(AURenderCallbackStruct); err3 = AudioUnitSetProperty(audio->device, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &input, size); if(err3) { CloseComponent(audio->device); ExtAudioFileDispose(audio->file); return false; } /* prepare audio device */ err3 = AudioUnitInitialize(audio->device); if(err3) { CloseComponent(audio->device); ExtAudioFileDispose(audio->file); return false; } /* start */ err3 = AudioOutputUnitStart(audio->device); if(err3) { AudioUnitUninitialize(audio->device); CloseComponent(audio->device); ExtAudioFileDispose(audio->file); return false; } return true; }
core_audio_sound* CCoreAudioSoundManager::LoadSoundFromFile(const CStdString& fileName) { FSRef fileRef; UInt32 size = 0; ExtAudioFileRef audioFile; OSStatus ret = FSPathMakeRef((const UInt8*) fileName.c_str(), &fileRef, false); ret = ExtAudioFileOpen(&fileRef, &audioFile); if (ret) { CLog::Log(LOGERROR, "CCoreAudioSoundManager::LoadSoundFromFile: Unable to open source file (%s). Error = 0x%08x (%4.4s)", fileName.c_str(), ret, CONVERT_OSSTATUS(ret)); return NULL; } core_audio_sound* pSound = new core_audio_sound; // Retrieve the format of the source file AudioStreamBasicDescription inputFormat; size = sizeof(inputFormat); ret = ExtAudioFileGetProperty(audioFile, kExtAudioFileProperty_FileDataFormat, &size, &inputFormat); if (ret) { CLog::Log(LOGERROR, "CCoreAudioSoundManager::LoadSoundFromFile: Unable to fetch source file format. Error = 0x%08x (%4.4s)", ret, CONVERT_OSSTATUS(ret)); delete pSound; return NULL; } // Set up format conversion. This is the format that will be produced by Read/Write calls. // Here we use the same format provided to the output AudioUnit ret = ExtAudioFileSetProperty(audioFile, kExtAudioFileProperty_ClientDataFormat, sizeof(AudioStreamBasicDescription), &m_OutputFormat); if (ret) { CLog::Log(LOGERROR, "CCoreAudioSoundManager::LoadSoundFromFile: Unable to set conversion format. Error = 0x%08x (%4.4s)", ret, CONVERT_OSSTATUS(ret)); delete pSound; return NULL; } // Retrieve the file size (in terms of the file's sample-rate, not the output sample-rate) UInt64 totalFrames; size = sizeof(totalFrames); ret = ExtAudioFileGetProperty(audioFile, kExtAudioFileProperty_FileLengthFrames, &size, &totalFrames); if (ret) { CLog::Log(LOGERROR, "CCoreAudioSoundManager::LoadSoundFromFile: Unable to fetch source file size. Error = 0x%08x (%4.4s)", ret, CONVERT_OSSTATUS(ret)); delete pSound; return NULL; } // Calculate the total number of converted frames to be read totalFrames *= (float)m_OutputFormat.mSampleRate / (float)inputFormat.mSampleRate; // TODO: Verify the accuracy of this // Allocate AudioBuffers UInt32 channelCount = m_OutputFormat.mChannelsPerFrame; pSound->buffer_list = (AudioBufferList*)calloc(1, sizeof(AudioBufferList) + sizeof(AudioBuffer) * (channelCount - kVariableLengthArray)); pSound->buffer_list->mNumberBuffers = channelCount; // One buffer per channel for deinterlaced pcm float* buffers = (float*)calloc(1, sizeof(float) * totalFrames * channelCount); for(int i = 0; i < channelCount; i++) { pSound->buffer_list->mBuffers[i].mNumberChannels = 1; // One channel per buffer for deinterlaced pcm pSound->buffer_list->mBuffers[i].mData = buffers + (totalFrames * i); pSound->buffer_list->mBuffers[i].mDataByteSize = totalFrames * sizeof(float); } // Read the entire file // TODO: Should we limit the total file length? UInt32 readFrames = totalFrames; ret = ExtAudioFileRead(audioFile, &readFrames, pSound->buffer_list); if (ret) { CLog::Log(LOGERROR, "CCoreAudioSoundManager::LoadSoundFromFile: Unable to read from file (%s). Error = 0x%08x (%4.4s)", fileName.c_str(), ret, CONVERT_OSSTATUS(ret)); delete pSound; return NULL; } pSound->total_frames = readFrames; // Store the actual number of frames read from the file. Rounding errors in calcuating the converted number of frames can truncate the read. // TODO: What do we do with files with more than 2 channels. Currently we just copy the first two and dump the rest. if (inputFormat.mChannelsPerFrame == 1) // Copy Left channel into Right if the source file is Mono memcpy(pSound->buffer_list->mBuffers[1].mData, pSound->buffer_list->mBuffers[0].mData, pSound->buffer_list->mBuffers[0].mDataByteSize); ret = ExtAudioFileDispose(audioFile); // Close the file. We have what we need. Not a lot to be done on failure. if (ret) CLog::Log(LOGERROR, "CCoreAudioSoundManager::LoadSoundFromFile: Unable to close file (%s). Error = 0x%08x (%4.4s)", fileName.c_str(), ret, CONVERT_OSSTATUS(ret)); pSound->ref_count = 1; // The caller holds a reference to this object now pSound->play_count = 0; return pSound; }
CoreAudioReadStream::CoreAudioReadStream(string path) : m_path(path), m_d(new D) { m_channelCount = 0; m_sampleRate = 0; if (!QFile(m_path).exists()) { throw FileNotFound(m_path); } QByteArray ba = m_path.toLocal8Bit(); CFURLRef url = CFURLCreateFromFileSystemRepresentation (kCFAllocatorDefault, (const UInt8 *)ba.data(), (CFIndex)ba.length(), false); //!!! how do we find out if the file open fails because of DRM protection? #if (MACOSX_DEPLOYMENT_TARGET <= 1040 && MAC_OS_X_VERSION_MIN_REQUIRED <= 1040) FSRef fsref; if (!CFURLGetFSRef(url, &fsref)) { // returns Boolean, not error code m_error = "CoreAudioReadStream: Error looking up FS ref (file not found?)"; throw FileReadFailed(m_path); } m_d->err = ExtAudioFileOpen(&fsref, &m_d->file); #else m_d->err = ExtAudioFileOpenURL(url, &m_d->file); #endif CFRelease(url); if (m_d->err) { m_error = "CoreAudioReadStream: Error opening file: code " + codestr(m_d->err); throw InvalidFileFormat(path, "failed to open audio file"); } if (!m_d->file) { m_error = "CoreAudioReadStream: Failed to open file, but no error reported!"; throw InvalidFileFormat(path, "failed to open audio file"); } UInt32 propsize = sizeof(AudioStreamBasicDescription); m_d->err = ExtAudioFileGetProperty (m_d->file, kExtAudioFileProperty_FileDataFormat, &propsize, &m_d->asbd); if (m_d->err) { m_error = "CoreAudioReadStream: Error in getting basic description: code " + codestr(m_d->err); ExtAudioFileDispose(m_d->file); throw FileOperationFailed(m_path, "get basic description", codestr(m_d->err)); } m_channelCount = m_d->asbd.mChannelsPerFrame; m_sampleRate = m_d->asbd.mSampleRate; cerr << "CoreAudioReadStream: " << m_channelCount << " channels, " << m_sampleRate << " Hz" << std::endl; m_d->asbd.mSampleRate = getSampleRate(); m_d->asbd.mFormatID = kAudioFormatLinearPCM; m_d->asbd.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked | kAudioFormatFlagsNativeEndian; m_d->asbd.mBitsPerChannel = sizeof(float) * 8; m_d->asbd.mBytesPerFrame = sizeof(float) * m_channelCount; m_d->asbd.mBytesPerPacket = sizeof(float) * m_channelCount; m_d->asbd.mFramesPerPacket = 1; m_d->asbd.mReserved = 0; m_d->err = ExtAudioFileSetProperty (m_d->file, kExtAudioFileProperty_ClientDataFormat, propsize, &m_d->asbd); if (m_d->err) { m_error = "CoreAudioReadStream: Error in setting client format: code " + codestr(m_d->err); throw FileOperationFailed(m_path, "set client format", codestr(m_d->err)); } m_d->buffer.mNumberBuffers = 1; m_d->buffer.mBuffers[0].mNumberChannels = m_channelCount; m_d->buffer.mBuffers[0].mDataByteSize = 0; m_d->buffer.mBuffers[0].mData = 0; }