| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- //
- // AudioInputStream.m
- // BDVRClientDemo
- //
- // Created by baidu on 16/6/17.
- // Copyright © 2016年 baidu. All rights reserved.
- //
- #import "AudioInputStream.h"
- #import <AudioToolbox/AudioToolbox.h>
- #import <AVFoundation/AVAudioSession.h>
- #include "AudioDataQueue.hpp"
- const int kk_recorder_buffers_number = 3;
- const int kk_recorder_bits_per_channel = 16;
- const int kk_recorder_channels_per_frame = 1;
- const int kk_recorder_frames_per_package = 1;
- @interface AudioInputStream ()
- {
- BOOL isRecording;
- AudioQueueRef audioQueue;
- AudioQueueBufferRef aqBuffers[kk_recorder_buffers_number];
- AudioDataQueue *audioData;
- }
- // Developer should set the status depens on your data flow.
- @property (nonatomic, assign) NSStreamStatus status;
- @property (nonatomic, assign) NSInteger sampleRate;
- @property (nonatomic, assign) float packageDuration;
- @end
- @implementation AudioInputStream
- @synthesize delegate;
- - (instancetype)init
- {
- if (self = [super init]) {
- _status = NSStreamStatusNotOpen;
- _sampleRate = 16000;
- _packageDuration = 0.08;
- isRecording = false;
- audioQueue = NULL;
- }
- return self;
- }
- - (void)open
- {
- /*
- ** any operation to open data source, do it here.
- */
- [self startRecording];
- }
- - (void)close
- {
- /*
- ** clean up the data source.
- */
- [self stopRecorder];
- }
- #pragma mark - Custom
- - (BOOL)hasBytesAvailable;
- {
- return YES;
- }
- - (NSStreamStatus)streamStatus;
- {
- return self.status;
- }
- - (NSInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)len
- {
- @synchronized (self) {
- return audioData->dequeSamples(buffer, (int)len, true);
- }
- }
- - (BOOL)getBuffer:(uint8_t * _Nullable *)buffer length:(NSUInteger *)len
- {
- return NO;
- }
- #pragma mark - Data Source
- - (void)stopRecorder
- {
- if (!isRecording) {
- return;
- }
- isRecording = false;
-
- if (audioQueue) {
- AudioQueueRef tmpQueue = audioQueue;
- audioQueue = nil;
- [self stopAudioQueue:tmpQueue];
- }
-
- @synchronized(self) {
- delete audioData;
- }
- }
- - (void)startRecording
- {
- [self clearupRecording];
-
- AudioStreamBasicDescription recorderFormat;
- [self setupRecorderFormat:&recorderFormat formatID:kAudioFormatLinearPCM];
-
- OSStatus ret = AudioQueueNewInput(&recorderFormat,
- input_buffer_handler,
- (__bridge void*)self, /* user data */
- NULL, /* run loop */
- NULL, /* run loop mode */
- 0, /* flags */
- &audioQueue);
-
- int bufferByteSize = [self computeRecordBufferSizeWithFormat:&recorderFormat];
- for (int i = 0; i < kk_recorder_buffers_number; ++i) {
- ret = AudioQueueAllocateBuffer(audioQueue, bufferByteSize, &aqBuffers[i]);
- ret = AudioQueueEnqueueBuffer(audioQueue, aqBuffers[i], 0, NULL);
- }
-
- ret = AudioQueueStart(audioQueue, NULL);
- if (ret) {
- ret = AudioQueueStart(audioQueue, NULL);
- }
-
- isRecording = YES;
- }
- - (void)recvRecorderData:(AudioQueueRef)inAQ inBuffer:(AudioQueueBufferRef)inBuffer inNumPackages:(UInt32)inNumPackages
- {
- @synchronized (self) {
- if (inNumPackages > 0) {
- audioData->queueAudio((const uint8_t *)inBuffer->mAudioData, inBuffer->mAudioDataByteSize);
- }
-
- if (isRecording) {
- AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL);
- }
- }
- }
- - (void)stopAudioQueue:(AudioQueueRef)audioQueueRef
- {
- OSStatus ret = AudioQueueStop(audioQueueRef, true);
- ret = AudioQueueDispose(audioQueueRef, false);
- }
- - (void)setupRecorderFormat:(AudioStreamBasicDescription*)format formatID:(UInt32)formatID
- {
- if (format == NULL) {
- return;
- }
-
- bzero((void*)format, sizeof(*format));
- format->mFormatID = formatID;
- format->mSampleRate = self.sampleRate;
- format->mChannelsPerFrame = kk_recorder_channels_per_frame;
-
- if (formatID == kAudioFormatLinearPCM) {
- format->mBitsPerChannel = kk_recorder_bits_per_channel;
- format->mFramesPerPacket = kk_recorder_frames_per_package;
- format->mBytesPerPacket = format->mBytesPerFrame = (format->mBitsPerChannel / 8) * format->mChannelsPerFrame;
- format->mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
- } else if (formatID == kAudioFormatULaw || formatID == kAudioFormatALaw) {
- format->mBitsPerChannel = kk_recorder_bits_per_channel;
- format->mFramesPerPacket = kk_recorder_frames_per_package;
- format->mBytesPerPacket = format->mBytesPerFrame = (format->mBitsPerChannel / 8) * format->mChannelsPerFrame;
- }
- }
- - (int)computeRecordBufferSizeWithFormat:(AudioStreamBasicDescription*)format
- {
- if (format == NULL) {
- return 0;
- }
-
- int packets, frames, bytes = 0;
-
- frames = (int)ceil(self.packageDuration * format->mSampleRate);
- if (format->mBytesPerFrame > 0) {
- bytes = frames * format->mBytesPerFrame;
- } else {
- UInt32 maxPacketSize;
- if (format->mBytesPerPacket > 0) {
- maxPacketSize = format->mBytesPerPacket; // constant packet size
- } else {
- UInt32 propertySize = sizeof(maxPacketSize);
- AudioQueueGetProperty(audioQueue, kAudioQueueProperty_MaximumOutputPacketSize, &maxPacketSize,
- &propertySize);
- }
-
- if (format->mFramesPerPacket > 0) {
- packets = frames / format->mFramesPerPacket;
- } else {
- packets = frames; // worst-case scenario: 1 frame in a packet
- }
-
- if (packets == 0) { // sanity check
- packets = 1;
- }
-
- bytes = packets * maxPacketSize;
- }
-
- return bytes;
- }
- - (void)clearupRecording
- {
- audioData = new AudioDataQueue(16000*2*2);
- audioData->reset();
- if (audioQueue) {
- AudioQueueDispose(audioQueue, TRUE);
- audioQueue = nil;
- }
- }
- #pragma mark - Static callback
- static void input_buffer_handler(void * inUserData,
- AudioQueueRef inAQ,
- AudioQueueBufferRef inBuffer,
- const AudioTimeStamp * inStartTime,
- UInt32 inNumPackets,
- const AudioStreamPacketDescription* inPacketDesc) {
- AudioInputStream* recorder = (__bridge AudioInputStream*)inUserData;
- if (recorder != nil) {
- [recorder recvRecorderData:inAQ inBuffer:inBuffer inNumPackages:inNumPackets];
- }
- }
- @end
|