Skip to content

Commit 24c0e10

Browse files
committed
支持8k 16k重采样
Change-Id: I49fc1b5cbfbaf7824878f38355cf3af20be57299
1 parent 9429a5a commit 24c0e10

File tree

10 files changed

+349
-17
lines changed

10 files changed

+349
-17
lines changed

Podfile.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ PODS:
113113
- nanopb/decode (1.30906.0)
114114
- nanopb/encode (1.30906.0)
115115
- PromisesObjC (1.2.12)
116-
- Protobuf (3.18.0)
116+
- Protobuf (3.18.1)
117117
- QCloudCore (5.5.2)
118118
- QCloudCOSXML/Transfer (5.5.2):
119119
- QCloudCore (= 5.5.2)
@@ -251,7 +251,7 @@ SPEC CHECKSUMS:
251251
MJRefresh: ed450d6eb9d3346a2cb033ab7eb6de090aeef437
252252
nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc
253253
PromisesObjC: 3113f7f76903778cf4a0586bd1ab89329a0b7b97
254-
Protobuf: 1a37ebea1338949e9ac35a3f06e80b3f536eec8d
254+
Protobuf: 0ac2cdc92fb5c33dab66dd1c4e9f9cc4c34d00ba
255255
QCloudCore: b91a762d280f0a80cc6f537fd186ac43a4a3025e
256256
QCloudCOSXML: a30ab17f45b0cbbcbb218a3677298498e8748a22
257257
SDWebImage: 624d6e296c69b244bcede364c72ae0430ac14681

Source/LinkSDKDemo/Video/P2P/Controller/TIoTDemoPreviewDeviceVC.m

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,10 +209,15 @@ - (void)getDeviceStatusWithType:(NSString *)singleType qualityType:(NSString *)q
209209
}
210210

211211
AWAudioConfig *config = [[AWAudioConfig alloc] init];
212-
config.bitrate = 100000;
212+
config.bitrate = 32000;
213213
config.channelCount = 1;
214214
config.sampleSize = 16;
215-
config.sampleRate = 44100;
215+
config.sampleRate = 8000;
216+
217+
// config.bitrate = 100000;
218+
// config.channelCount = 1;
219+
// config.sampleSize = 16;
220+
// config.sampleRate = 44100;
216221
[[TIoTCoreXP2PBridge sharedInstance] sendVoiceToServer:self.deviceName?:@"" channel:channel audioConfig:config];
217222
}
218223

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
2+
3+
#import <Foundation/Foundation.h>
4+
#import <AVFoundation/AVFoundation.h>
5+
#import <AudioToolbox/AudioToolbox.h>
6+
7+
@interface AWAACEncoder : NSObject
8+
9+
@property (nonatomic) dispatch_queue_t encoderQueue;
10+
@property (nonatomic) dispatch_queue_t callbackQueue;
11+
@property (nonatomic, assign)Float64 sample_rate;
12+
13+
- (void) encodeSampleBuffer:(CMSampleBufferRef)sampleBuffer completionBlock:(void (^)(NSData *encodedData, NSError* error))completionBlock;
14+
15+
16+
@end
Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
2+
3+
#import "AWAACEncoder.h"
4+
5+
@interface AWAACEncoder()
6+
@property (nonatomic) AudioConverterRef audioConverter;
7+
@property (nonatomic) uint8_t *aacBuffer;
8+
@property (nonatomic) NSUInteger aacBufferSize;
9+
@property (nonatomic) char *pcmBuffer;
10+
@property (nonatomic) size_t pcmBufferSize;
11+
12+
@end
13+
14+
@implementation AWAACEncoder
15+
16+
- (void) dealloc {
17+
AudioConverterDispose(_audioConverter);
18+
free(_aacBuffer);
19+
}
20+
21+
- (id) init {
22+
if (self = [super init]) {
23+
_encoderQueue = dispatch_queue_create("AAC Encoder Queue", DISPATCH_QUEUE_SERIAL);
24+
_callbackQueue = dispatch_queue_create("AAC Encoder Callback Queue", DISPATCH_QUEUE_SERIAL);
25+
_audioConverter = NULL;
26+
_pcmBufferSize = 0;
27+
_pcmBuffer = NULL;
28+
_aacBufferSize = 1024;
29+
_aacBuffer = malloc(_aacBufferSize * sizeof(uint8_t));
30+
memset(_aacBuffer, 0, _aacBufferSize);
31+
}
32+
return self;
33+
}
34+
35+
/**
36+
* 设置编码参数
37+
*
38+
* @param sampleBuffer 音频
39+
*/
40+
- (void) setupEncoderFromSampleBuffer:(CMSampleBufferRef)sampleBuffer {
41+
AudioStreamBasicDescription inAudioStreamBasicDescription = *CMAudioFormatDescriptionGetStreamBasicDescription((CMAudioFormatDescriptionRef)CMSampleBufferGetFormatDescription(sampleBuffer));
42+
NSLog(@"pcm---samplerate-->%f, channel-->%d",inAudioStreamBasicDescription.mSampleRate, inAudioStreamBasicDescription.mChannelsPerFrame);
43+
44+
AudioStreamBasicDescription outAudioStreamBasicDescription = {0};
45+
outAudioStreamBasicDescription.mSampleRate = _sample_rate;
46+
outAudioStreamBasicDescription.mFormatID = kAudioFormatMPEG4AAC;
47+
outAudioStreamBasicDescription.mFormatFlags = kMPEG4Object_AAC_LC;
48+
outAudioStreamBasicDescription.mBytesPerPacket = 0;
49+
outAudioStreamBasicDescription.mFramesPerPacket = 1024;
50+
outAudioStreamBasicDescription.mBytesPerFrame = 0;
51+
outAudioStreamBasicDescription.mChannelsPerFrame = 1; // 声道数
52+
outAudioStreamBasicDescription.mBitsPerChannel = 0; // 压缩格式设置为0
53+
outAudioStreamBasicDescription.mReserved = 0; // 8字节对齐,填0.
54+
AudioClassDescription *description = [self getAudioClassDescriptionWithType:kAudioFormatMPEG4AAC fromManufacturer:kAppleSoftwareAudioCodecManufacturer]; //软编
55+
56+
OSStatus status = AudioConverterNewSpecific(&inAudioStreamBasicDescription, &outAudioStreamBasicDescription, 1, description, &_audioConverter); // 创建转换器
57+
if (status != 0) {
58+
NSLog(@"setup converter: %d", (int)status);
59+
}
60+
}
61+
62+
/**
63+
* 获取编解码器
64+
*
65+
* @param type 编码格式
66+
* @param manufacturer 软/硬编
67+
*
68+
编解码器(codec)指的是一个能够对一个信号或者一个数据流进行变换的设备或者程序。这里指的变换既包括将 信号或者数据流进行编码(通常是为了传输、存储或者加密)或者提取得到一个编码流的操作,也包括为了观察或者处理从这个编码流中恢复适合观察或操作的形式的操作。编解码器经常用在视频会议和流媒体等应用中。
69+
* @return 指定编码器
70+
*/
71+
- (AudioClassDescription *)getAudioClassDescriptionWithType:(UInt32)type fromManufacturer:(UInt32)manufacturer {
72+
static AudioClassDescription desc;
73+
74+
UInt32 encoderSpecifier = type;
75+
OSStatus st;
76+
77+
UInt32 size;
78+
st = AudioFormatGetPropertyInfo(kAudioFormatProperty_Encoders,
79+
sizeof(encoderSpecifier),
80+
&encoderSpecifier,
81+
&size);
82+
if (st) {
83+
NSLog(@"error getting audio format propery info: %d", (int)(st));
84+
return nil;
85+
}
86+
87+
unsigned int count = size / sizeof(AudioClassDescription);
88+
AudioClassDescription descriptions[count];
89+
st = AudioFormatGetProperty(kAudioFormatProperty_Encoders,
90+
sizeof(encoderSpecifier),
91+
&encoderSpecifier,
92+
&size,
93+
descriptions);
94+
if (st) {
95+
NSLog(@"error getting audio format propery: %d", (int)(st));
96+
return nil;
97+
}
98+
99+
for (unsigned int i = 0; i < count; i++) {
100+
if ((type == descriptions[i].mSubType) &&
101+
(manufacturer == descriptions[i].mManufacturer)) {
102+
memcpy(&desc, &(descriptions[i]), sizeof(desc));
103+
return &desc;
104+
}
105+
}
106+
107+
return nil;
108+
}
109+
110+
111+
/**
112+
* A callback function that supplies audio data to convert. This callback is invoked repeatedly as the converter is ready for new input data.
113+
114+
*/
115+
OSStatus inInputDataProc(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPackets, AudioBufferList *ioData, AudioStreamPacketDescription **outDataPacketDescription, void *inUserData)
116+
{
117+
AWAACEncoder *encoder = (__bridge AWAACEncoder *)(inUserData);
118+
UInt32 requestedPackets = *ioNumberDataPackets;
119+
120+
size_t copiedSamples = [encoder copyPCMSamplesIntoBuffer:ioData];
121+
if (copiedSamples < requestedPackets) {
122+
//PCM 缓冲区还没满
123+
*ioNumberDataPackets = 0;
124+
return -1;
125+
}
126+
*ioNumberDataPackets = 1;
127+
128+
return noErr;
129+
}
130+
131+
/**
132+
* 填充PCM到缓冲区
133+
*/
134+
- (size_t) copyPCMSamplesIntoBuffer:(AudioBufferList*)ioData {
135+
size_t originalBufferSize = _pcmBufferSize;
136+
if (!originalBufferSize) {
137+
return 0;
138+
}
139+
ioData->mBuffers[0].mData = _pcmBuffer;
140+
ioData->mBuffers[0].mDataByteSize = (int)_pcmBufferSize;
141+
_pcmBuffer = NULL;
142+
_pcmBufferSize = 0;
143+
return originalBufferSize;
144+
}
145+
146+
147+
- (void) encodeSampleBuffer:(CMSampleBufferRef)sampleBuffer completionBlock:(void (^)(NSData * encodedData, NSError* error))completionBlock {
148+
CFRetain(sampleBuffer);
149+
dispatch_async(_encoderQueue, ^{
150+
if (!_audioConverter) {
151+
[self setupEncoderFromSampleBuffer:sampleBuffer];
152+
}
153+
CMBlockBufferRef blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer);
154+
CFRetain(blockBuffer);
155+
OSStatus status = CMBlockBufferGetDataPointer(blockBuffer, 0, NULL, &_pcmBufferSize, &_pcmBuffer);
156+
NSError *error = nil;
157+
if (status != kCMBlockBufferNoErr) {
158+
error = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil];
159+
}
160+
memset(_aacBuffer, 0, _aacBufferSize);
161+
162+
AudioBufferList outAudioBufferList = {0};
163+
outAudioBufferList.mNumberBuffers = 1;
164+
outAudioBufferList.mBuffers[0].mNumberChannels = 1;
165+
outAudioBufferList.mBuffers[0].mDataByteSize = (int)_aacBufferSize;
166+
outAudioBufferList.mBuffers[0].mData = _aacBuffer;
167+
AudioStreamPacketDescription *outPacketDescription = NULL;
168+
UInt32 ioOutputDataPacketSize = 1;
169+
// Converts data supplied by an input callback function, supporting non-interleaved and packetized formats.
170+
// Produces a buffer list of output data from an AudioConverter. The supplied input callback function is called whenever necessary.
171+
status = AudioConverterFillComplexBuffer(_audioConverter, inInputDataProc, (__bridge void *)(self), &ioOutputDataPacketSize, &outAudioBufferList, outPacketDescription);
172+
NSData *data = nil;
173+
if (status == 0) {
174+
NSData *rawAAC = [NSData dataWithBytes:outAudioBufferList.mBuffers[0].mData length:outAudioBufferList.mBuffers[0].mDataByteSize];
175+
NSData *adtsHeader = [self adtsDataForPacketLength:rawAAC.length];
176+
NSMutableData *fullData = [NSMutableData dataWithData:adtsHeader];
177+
[fullData appendData:rawAAC];
178+
data = fullData;
179+
} else {
180+
error = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil];
181+
}
182+
if (completionBlock) {
183+
dispatch_async(_callbackQueue, ^{
184+
completionBlock(data, error);
185+
});
186+
}
187+
CFRelease(sampleBuffer);
188+
CFRelease(blockBuffer);
189+
});
190+
}
191+
192+
- (NSData*) adtsDataForPacketLength:(NSUInteger)packetLength {
193+
int adtsLength = 7;
194+
char *packet = malloc(sizeof(char) * adtsLength);
195+
// Variables Recycled by addADTStoPacket
196+
int profile = 2; //AAC LC
197+
//39=MediaCodecInfo.CodecProfileLevel.AACObjectELD;
198+
int freqIdx = 4; //44.1KHz
199+
// if (_sample_rate == 44100) {
200+
// freqIdx = 4;
201+
// }else if (_sample_rate == 16000) {
202+
// freqIdx = 8;
203+
// }else if (_sample_rate == 8000) {
204+
// freqIdx = 11;
205+
// }
206+
// int freqIdx = 11; //44.1KHz
207+
/* 其中,samplingFreguencyIndex 对应关系如下:
208+
0 - 96000
209+
1 - 88200
210+
2 - 64000
211+
3 - 48000
212+
4 - 44100
213+
5 - 32000
214+
6 - 24000
215+
7 - 22050
216+
8 - 16000
217+
9 - 12000
218+
10 - 11025
219+
11 - 8000
220+
12 - 7350
221+
13 - Reserved
222+
14 - Reserved
223+
15 - frequency is written explictly
224+
*/
225+
int chanCfg = 1; //MPEG-4 Audio Channel Configuration. 1 Channel front-center
226+
NSUInteger fullLength = adtsLength + packetLength;
227+
// fill in ADTS data
228+
packet[0] = (char)0xFF; // 11111111 = syncword
229+
packet[1] = (char)0xF9; // 1111 1 00 1 = syncword MPEG-2 Layer CRC
230+
packet[2] = (char)(((profile-1)<<6) + (freqIdx<<2) +(chanCfg>>2));
231+
packet[3] = (char)(((chanCfg&3)<<6) + (fullLength>>11));
232+
packet[4] = (char)((fullLength&0x7FF) >> 3);
233+
packet[5] = (char)(((fullLength&7)<<5) + 0x1F);
234+
packet[6] = (char)0xFC;
235+
NSData *data = [NSData dataWithBytesNoCopy:packet length:adtsLength freeWhenDone:YES];
236+
return data;
237+
}
238+
239+
240+
@end

Source/SDK/LinkVideo/AudioFLV/AWAVCapture.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939

4040
-(void) sendAudioSampleBuffer:(CMSampleBufferRef) sampleBuffer;
4141
-(void) sendAudioPcmData:(NSData *)audioData;
42+
-(void) sendAudioAACData:(NSData *)audioData;
4243
-(void) sendFlvAudioTag:(aw_flv_audio_tag *)flvAudioTag;
4344

4445
@end

Source/SDK/LinkVideo/AudioFLV/AWAVCapture.m

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ -(void) updateFps:(NSInteger) fps{
9191
}
9292
}
9393

94-
-(BOOL) startCapture {
94+
-(BOOL) startCapture {
9595
if (!self.audioConfig) {
9696
NSLog(@"one of videoConfig and audioConfig must be NON-NULL");
9797
return NO;
@@ -174,6 +174,15 @@ -(void) sendAudioPcmData:(NSData *)pcmData toEncodeQueue:(NSOperationQueue *) en
174174
}];
175175
}
176176

177+
-(void) sendAudioAACData:(NSData *)aacData toEncodeQueue:(NSOperationQueue *) encodeQueue toSendQueue:(NSOperationQueue *) sendQueue{
178+
__weak typeof(self) weakSelf = self;
179+
[encodeQueue addOperationWithBlock:^{
180+
if (weakSelf.isCapturing) {
181+
aw_flv_audio_tag *audio_tag = [weakSelf.encoderManager.audioEncoder encodeAACDataToFlvTag:aacData];
182+
[weakSelf sendFlvAudioTag:audio_tag toSendQueue:sendQueue];
183+
}
184+
}];
185+
}
177186

178187
-(void) sendFlvAudioTag:(aw_flv_audio_tag *)audio_tag toSendQueue:(NSOperationQueue *) sendQueue{
179188
__weak typeof(self) weakSelf = self;
@@ -203,7 +212,7 @@ -(void) sendSpsPpsAndAudioSpecificConfigTagToSendQueue:(NSOperationQueue *) send
203212
return;
204213
}
205214
//flv header hhhhhhhhhhhhhhhhhhhh
206-
// aw_write_audio_header();
215+
aw_write_audio_header();
207216

208217

209218
//audio specific config tag
@@ -226,6 +235,14 @@ -(void) sendAudioPcmData:(NSData *)audioData{
226235
[self sendAudioPcmData:audioData toEncodeQueue:self.encodeSampleOpQueue toSendQueue:self.sendSampleOpQueue];
227236
}
228237

238+
-(void) sendAudioAACData:(NSData *)audioData {
239+
if (audioData == nil) {
240+
NSLog(@"audiodata is nil");
241+
return;
242+
}
243+
[self sendAudioAACData:audioData toEncodeQueue:self.encodeSampleOpQueue toSendQueue:self.sendSampleOpQueue];
244+
}
245+
229246
-(void) sendFlvAudioTag:(aw_flv_audio_tag *)flvAudioTag{
230247
[self sendFlvAudioTag:flvAudioTag toSendQueue:self.sendSampleOpQueue];
231248
}

Source/SDK/LinkVideo/AudioFLV/AWAudioEncoder.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
//编码
77
-(aw_flv_audio_tag *) encodePCMDataToFlvTag:(NSData *)pcmData;
88

9+
-(aw_flv_audio_tag *) encodeAACDataToFlvTag:(NSData *)aacData;
10+
911
-(aw_flv_audio_tag *) encodeAudioSampleBufToFlvTag:(CMSampleBufferRef)audioSample;
1012

1113
//创建 audio specific config

0 commit comments

Comments
 (0)