Мне нужно воспроизвести необработанные данные PCM (16 бит) с использованием CoreAudio на OS X. Я получаю его из сети с использованием сокета UDP (на стороне передаются данные с микрофона) ,
Проблема в том, что все, что я слышу сейчас, это небольшой шум трещины, а затем только молчание.
Я пытаюсь воспроизвести данные с помощью AudioQueue. Настройка я это так:Воспроизведение raw pcm из сети с использованием AudioQueue в CoreAudio
// Set up stream format fields
AudioStreamBasicDescription streamFormat;
streamFormat.mSampleRate = 44100;
streamFormat.mFormatID = kAudioFormatLinearPCM;
streamFormat.mFormatFlags = kLinearPCMFormatFlagIsBigEndian | kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
streamFormat.mBitsPerChannel = 16;
streamFormat.mChannelsPerFrame = 1;
streamFormat.mBytesPerPacket = 2 * streamFormat.mChannelsPerFrame;
streamFormat.mBytesPerFrame = 2 * streamFormat.mChannelsPerFrame;
streamFormat.mFramesPerPacket = 1;
streamFormat.mReserved = 0;
OSStatus err = noErr;
// create the audio queue
err = AudioQueueNewOutput(&streamFormat, MyAudioQueueOutputCallback, myData, NULL, NULL, 0, &myData->audioQueue);
if (err)
{ PRINTERROR("AudioQueueNewOutput"); myData->failed = true; result = false;}
// allocate audio queue buffers
for (unsigned int i = 0; i < kNumAQBufs; ++i) {
err = AudioQueueAllocateBuffer(myData->audioQueue, kAQBufSize, &myData->audioQueueBuffer[i]);
if (err)
{ PRINTERROR("AudioQueueAllocateBuffer"); myData->failed = true; break; result = false;}
}
// listen for kAudioQueueProperty_IsRunning
err = AudioQueueAddPropertyListener(myData->audioQueue, kAudioQueueProperty_IsRunning, MyAudioQueueIsRunningCallback, myData);
if (err)
{ PRINTERROR("AudioQueueAddPropertyListener"); myData->failed = true; result = false;}
MyAudioQueueOutputCallback является:
void MyAudioQueueOutputCallback(void* inClientData,
AudioQueueRef inAQ,
AudioQueueBufferRef inBuffer)
{
// this is called by the audio queue when it has finished decoding our data.
// The buffer is now free to be reused.
MyData* myData = (MyData*)inClientData;
unsigned int bufIndex = MyFindQueueBuffer(myData, inBuffer);
// signal waiting thread that the buffer is free.
pthread_mutex_lock(&myData->mutex);
myData->inuse[bufIndex] = false;
pthread_cond_signal(&myData->cond);
pthread_mutex_unlock(&myData->mutex);
}
MyAudioQueueIsRunningCallback является:
void MyAudioQueueIsRunningCallback(void* inClientData,
AudioQueueRef inAQ,
AudioQueuePropertyID inID)
{
MyData* myData = (MyData*)inClientData;
UInt32 running;
UInt32 size;
OSStatus err = AudioQueueGetProperty(inAQ, kAudioQueueProperty_IsRunning, &running, &size);
if (err) { PRINTERROR("get kAudioQueueProperty_IsRunning"); return; }
if (!running) {
pthread_mutex_lock(&myData->mutex);
pthread_cond_signal(&myData->done);
pthread_mutex_unlock(&myData->mutex);
}
}
и MyData является:
struct MyData
{
AudioQueueRef audioQueue; // the audio queue
AudioQueueBufferRef audioQueueBuffer[kNumAQBufs]; // audio queue buffers
AudioStreamPacketDescription packetDescs[kAQMaxPacketDescs]; // packet descriptions for enqueuing audio
unsigned int fillBufferIndex; // the index of the audioQueueBuffer that is being filled
size_t bytesFilled; // how many bytes have been filled
size_t packetsFilled; // how many packets have been filled
bool inuse[kNumAQBufs]; // flags to indicate that a buffer is still in use
bool started; // flag to indicate that the queue has been started
bool failed; // flag to indicate an error occurred
bool finished; // flag to inidicate that termination is requested
pthread_mutex_t mutex; // a mutex to protect the inuse flags
pthread_mutex_t mutex2; // a mutex to protect the AudioQueue buffer
pthread_cond_t cond; // a condition varable for handling the inuse flags
pthread_cond_t done; // a condition varable for handling the inuse flags
};
Я извиняюсь, если я отправил слишком много кода - надеюсь это помогает кому-то понять, что именно я делаю.
В основном мой код основан на коде this, который является версией AudioFileStreamExample из Mac Developer Library, адаптированной для работы с данными CBR.
Также я просмотрел сообщение this и попробовал AudioStreamBasicОписание, описанное там. И попытался сменить флаги на Маленький или Большой Эндиан. Это не сработало.
Я посмотрел на некоторые другие сообщения здесь и в других ресурсах при поиске аналогичной проблемы, например, я проверил порядок моих данных PCM. Я просто не могу разместить более двух ссылок.
Пожалуйста, помогите мне понять, что я делаю неправильно! Может быть, я должен отказаться от этого способа и сразу использовать аудиоустройства? Я просто очень новичок в CoreAudio и надеюсь, что средний уровень CoreAudio поможет мне решить эту проблему.
P.S. Извините за мой английский, я старался как могу.
Как выглядит 'MyFindQueueBuffer'? – sbooth
просто так: 'INT MyFindQueueBuffer (MyData * MyData, AudioQueueBufferRef InBuffer) { для (неподписанных INT I = 0; я audioQueueBuffer [я]) return i; } return -1; } ' –
foobar
извините, перепутал с linebreaks%) – foobar