У меня есть следующая проблема: у меня есть многоканальный микшер (не моя реализация) с использованием AudioToolbox Framework. Я хочу получить значение основного объема на выходе после объединения всех каналов.Возможно ли использовать данные AudioUnit или передавать данные AudioUnit для целей измерения
Любая помощь будет оценена!
EDIT
Я пытаюсь использовать AudioQueueLevelMeterState для возвращения текущего уровня громкости в диапазоне от 0 до 1. Как я прохожу AUGraph или AudioUnit для звуковых сообщений? Может быть, это немного непонятно вопрос, но все-таки ...
-(float)volumeLevel
{
UInt32 trueValue = true;
AudioQueueSetProperty(audioQueue,kAudioQueueProperty_EnableLevelMetering,&trueValue,sizeof (UInt32));
UInt32 dataSize = sizeof(AudioQueueLevelMeterState) * _streamFormat.mChannelsPerFrame;
AudioQueueLevelMeterState *level = (AudioQueueLevelMeterState *)malloc(dataSize);
float channelAvg = 0;
OSStatus rc = AudioQueueGetProperty(audioQueue, kAudioQueueProperty_CurrentLevelMeter, level, &dataSize);
if (rc) {
NSLog(@"AudioQueueGetProperty(CurrentLevelMeter) returned %d", (int)rc);
} else {
for (int i = 0; i < _streamFormat.mChannelsPerFrame; i++) {
channelAvg += level[i].mPeakPower;
}
}
free(level);
printf("Current peak :%f", channelAvg);
return channelAvg;
}
Здесь фактическая отрезала реализации смесителя:
typedef struct {
UInt32 totalFrames;
UInt32 nextFrame;
UInt32 playedFrames;
UInt32 playedLoops;
UInt32 activeLoops;
Float32 volume;
AudioUnitSampleType *dataLeft;
AudioUnitSampleType *dataRight;
} AudioMixerChannel, *AudioMixerChannelPointer;
static OSStatus inputRenderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData);
void audioRouteChangeListenerCallback (void *inUserData, AudioSessionPropertyID inPropertyID, UInt32 inPropertyValueSize, const void *inPropertyValue);
void checkError(OSStatus error, const char *operation);
@interface AudioMixer()
{
AudioStreamBasicDescription _streamFormat;
AUGraph _graph;
AUNode _iONode;
AUNode _mixerNode;
AudioUnit _mixerUnit;
AudioMixerChannel _channels[TRACK_MAX_CHANNELS];
}
@end
@implementation AudioMixer
- (id) init
{
self = [super init];
if (self) {
size_t bytesPerSample = sizeof(AudioUnitSampleType);
_streamFormat.mFormatID = kAudioFormatLinearPCM;
_streamFormat.mFormatFlags = kAudioFormatFlagsAudioUnitCanonical;
_streamFormat.mBytesPerPacket = (int)bytesPerSample;
_streamFormat.mFramesPerPacket = 1;
_streamFormat.mBytesPerFrame = (int)bytesPerSample;
_streamFormat.mChannelsPerFrame = 2;
_streamFormat.mBitsPerChannel = 8 * (int)bytesPerSample;
_streamFormat.mSampleRate = 44100.0;
checkError(NewAUGraph(&_graph), "NewAUGraph");
checkError(AUGraphOpen(_graph), "AUGraphOpen");
checkError(AUGraphInitialize(_graph), "AUGraphInitialize");
AudioComponentDescription iOUnitDescription;
iOUnitDescription.componentType = kAudioUnitType_Output;
iOUnitDescription.componentSubType = kAudioUnitSubType_RemoteIO;
iOUnitDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
iOUnitDescription.componentFlags = 0;
iOUnitDescription.componentFlagsMask = 0;
checkError(AUGraphAddNode(_graph, &iOUnitDescription, &_iONode), "AUGraphNewNode failed for I/O unit");
AudioComponentDescription MixerUnitDescription;
MixerUnitDescription.componentType = kAudioUnitType_Mixer;
MixerUnitDescription.componentSubType = kAudioUnitSubType_MultiChannelMixer;
MixerUnitDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
MixerUnitDescription.componentFlags = 0;
MixerUnitDescription.componentFlagsMask = 0;
checkError(AUGraphAddNode(_graph, &MixerUnitDescription, &_mixerNode), "AUGraphNewNode failed for Mixer unit");
checkError(AUGraphNodeInfo(_graph, _mixerNode, NULL, &_mixerUnit), "AUGraphNodeInfo - mixer unit");
checkError(AUGraphConnectNodeInput(_graph, _mixerNode, 0, _iONode, 0), "AUGraphConnectNodeInput");
for(int i=0; i<TRACK_MAX_CHANNELS; i++) {
AURenderCallbackStruct inputCallbackStruct;
inputCallbackStruct.inputProc = &inputRenderCallback;
inputCallbackStruct.inputProcRefCon = _channels;
checkError(AUGraphSetNodeInputCallback(_graph, _mixerNode, i, &inputCallbackStruct), "AUGraphSetNodeInputCallback");
}
}
return self;
}