私のアプリでは、デバイスのデフォルトのマイクからサウンドを録音し、RTSP サーバーに送信してさらにストリーミングする必要があります。
私のレコーダーの状態構造は次のとおりです。
typedef struct AQRecorderState {
AudioStreamBasicDescription mDataFormat; // 2
AudioQueueRef mQueue; // 3
AudioQueueBufferRef mBuffers[kNumberRecordBuffers];// 4
AudioFileID mAudioFile; // 5
UInt32 bufferByteSize; // 6
SInt64 mCurrentPacket; // 7
bool mIsRunning; // 8
}AQRecorderState;
録音用の私の設定パラメータは次のとおりです。
ars.mDataFormat.mSampleRate = 44100;
ars.mDataFormat.mChannelsPerFrame = 1;
ars.mDataFormat.mFramesPerPacket = 1;
ars.mDataFormat.mBitsPerChannel = 16;
ars.mDataFormat.mBytesPerFrame = ars.mDataFormat.mChannelsPerFrame * sizeof (SInt16); // BYTES_PER_FRAME;
ars.mDataFormat.mBytesPerPacket = ars.mDataFormat.mChannelsPerFrame * sizeof (SInt16); // BYTES_PER_PACKET;
/*----------------- FORMAT -------------------*/
ars.mDataFormat.mFormatID = kAudioFormatLinearPCM;
ars.mDataFormat.mFormatFlags = kLinearPCMFormatFlagIsBigEndian | kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
// derive the buffer size
DeriveBufferSize(ars.mQueue, ars.mDataFormat, kBufferSeconds, &ars.bufferByteSize);
// create the queue
AudioQueueNewInput(&ars.mDataFormat,
AQInputCallback,
(__bridge void *)(self),
NULL,
kCFRunLoopCommonModes,
0,
&ars.mQueue);
// set the magic cookie for the queue
setMagicCookieForFile(ars.mQueue, ars.mAudioFile);
// allocate and enque the recording buffers
for (int i=0; i<kNumberRecordBuffers; i++){
AudioQueueAllocateBuffer(ars.mQueue, ars.bufferByteSize, &ars.mBuffers[i]);
AudioQueueEnqueueBuffer(ars.mQueue, ars.mBuffers[i], 0, NULL);
}
// set current packet index and run state
ars.mCurrentPacket = 0;
ars.mIsRunning = true;
// start the recording
AudioQueueStart(ars.mQueue, NULL);
そして、私の入力コールバックは次のようになります:
static void AQInputCallback(void *aqRecorderState,
AudioQueueRef inQ,
AudioQueueBufferRef inBuffer,
const AudioTimeStamp *timestamp,
unsigned long inNumPackets,
const AudioStreamPacketDescription *mDataFormat)
{
NSLog(@"........Callback called");
AppDelegate *THIS=(__bridge AppDelegate *)aqRecorderState;
AQRecorderState *pArs = &(THIS->ars);
if (inNumPackets > 0) {
write_audio_frame(THIS->oc, THIS->audio_st);
// Stream audio frame
uint8_t *data;
AVCodecContext *codec;
AVPacket packet;
uint32_t size = inBuffer->mAudioDataByteSize;
long sample_time_ms = (long)(timestamp->mSampleTime * 1000 / SAMPLE_RATE);
codec = THIS->audio_st->codec;
data = av_malloc(size*100);
if (!data) {
fprintf(stderr, "Couldn't allocate data for audio_frame\n");
exit(1);
}
NSLog(@"Size 1 : %d",size);
av_init_packet(&packet);
packet.size = avcodec_encode_audio(codec, data, size, inBuffer->mAudioData);
NSLog(@"Size 2: %d",packet.size);
packet.data = data;
packet.pts = sample_time_ms;
packet.dts = sample_time_ms;
packet.flags |= AV_PKT_FLAG_KEY;
packet.duration = (size * 8 * 1024 * 1000000)/BITS_PER_CHANNEL;
packet.stream_index = THIS->audio_st->index; //audio_st->index
pArs->mCurrentPacket += inNumPackets; // advance packet index pointer
if (av_interleaved_write_frame(THIS->oc, &packet) != 0) {
exit(1);
}
pArs->mCurrentPacket += inNumPackets; // advance packet index pointer
av_free(data);
}
}
入力コールバックでデータを取得しています。ファイルに書き込んで再生するとうまくいきますが、ファイルに保存せずにそのデータを RTSP サーバーに直接送信する必要があります。
注:av_interleaved_write_frame()
フレームをサーバーに書き込むために使用していますが、問題はAVPacket
入力コールバックでの変換にあると思います。そのため、サーバー側で「順不同」のパケットを取得しています。
インターネットであらゆる場所を検索しましたが、機能するものが見つかりません。誰かがそれについて何か考えているなら助けてください。