DOUAudioDecoder.m 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. /* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
  2. /*
  3. * DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
  4. *
  5. * https://github.com/douban/DOUAudioStreamer
  6. *
  7. * Copyright 2013-2016 Douban Inc. All rights reserved.
  8. *
  9. * Use and distribution licensed under the BSD license. See
  10. * the LICENSE file for full text.
  11. *
  12. * Authors:
  13. * Chongyu Zhu <i@lembacon.com>
  14. *
  15. */
  16. #import "DOUAudioDecoder.h"
  17. #import "DOUAudioFileProvider.h"
  18. #import "DOUAudioPlaybackItem.h"
  19. #import "DOUAudioLPCM.h"
  20. #include <AudioToolbox/AudioToolbox.h>
  21. #include <pthread.h>
  22. typedef struct {
  23. AudioFileID afid;
  24. SInt64 pos;
  25. void *srcBuffer;
  26. UInt32 srcBufferSize;
  27. AudioStreamBasicDescription srcFormat;
  28. UInt32 srcSizePerPacket;
  29. UInt32 numPacketsPerRead;
  30. AudioStreamPacketDescription *pktDescs;
  31. } AudioFileIO;
  32. typedef struct {
  33. AudioStreamBasicDescription inputFormat;
  34. AudioStreamBasicDescription outputFormat;
  35. AudioFileIO afio;
  36. SInt64 decodeValidFrames;
  37. AudioStreamPacketDescription *outputPktDescs;
  38. UInt32 outputBufferSize;
  39. void *outputBuffer;
  40. UInt32 numOutputPackets;
  41. SInt64 outputPos;
  42. pthread_mutex_t mutex;
  43. } DecodingContext;
  44. @interface DOUAudioDecoder () {
  45. @private
  46. DOUAudioPlaybackItem *_playbackItem;
  47. DOUAudioLPCM *_lpcm;
  48. AudioStreamBasicDescription _outputFormat;
  49. AudioConverterRef _audioConverter;
  50. NSUInteger _bufferSize;
  51. DecodingContext _decodingContext;
  52. BOOL _decodingContextInitialized;
  53. }
  54. @end
  55. @implementation DOUAudioDecoder
  56. @synthesize playbackItem = _playbackItem;
  57. @synthesize lpcm = _lpcm;
  58. + (AudioStreamBasicDescription)defaultOutputFormat
  59. {
  60. static AudioStreamBasicDescription defaultOutputFormat;
  61. static dispatch_once_t onceToken;
  62. dispatch_once(&onceToken, ^{
  63. defaultOutputFormat.mFormatID = kAudioFormatLinearPCM;
  64. defaultOutputFormat.mSampleRate = 44100;
  65. defaultOutputFormat.mBitsPerChannel = 16;
  66. defaultOutputFormat.mChannelsPerFrame = 2;
  67. defaultOutputFormat.mBytesPerFrame = defaultOutputFormat.mChannelsPerFrame * (defaultOutputFormat.mBitsPerChannel / 8);
  68. defaultOutputFormat.mFramesPerPacket = 1;
  69. defaultOutputFormat.mBytesPerPacket = defaultOutputFormat.mFramesPerPacket * defaultOutputFormat.mBytesPerFrame;
  70. defaultOutputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
  71. });
  72. return defaultOutputFormat;
  73. }
  74. + (instancetype)decoderWithPlaybackItem:(DOUAudioPlaybackItem *)playbackItem
  75. bufferSize:(NSUInteger)bufferSize
  76. {
  77. return [[[self class] alloc] initWithPlaybackItem:playbackItem
  78. bufferSize:bufferSize];
  79. }
  80. - (instancetype)initWithPlaybackItem:(DOUAudioPlaybackItem *)playbackItem
  81. bufferSize:(NSUInteger)bufferSize
  82. {
  83. self = [super init];
  84. if (self) {
  85. _playbackItem = playbackItem;
  86. _bufferSize = bufferSize;
  87. _lpcm = [[DOUAudioLPCM alloc] init];
  88. _outputFormat = [[self class] defaultOutputFormat];
  89. [self _createAudioConverter];
  90. if (_audioConverter == NULL) {
  91. return nil;
  92. }
  93. }
  94. return self;
  95. }
  96. - (void)dealloc
  97. {
  98. if (_decodingContextInitialized) {
  99. [self tearDown];
  100. }
  101. if (_audioConverter != NULL) {
  102. AudioConverterDispose(_audioConverter);
  103. }
  104. }
  105. - (void)_createAudioConverter
  106. {
  107. AudioStreamBasicDescription inputFormat = [_playbackItem fileFormat];
  108. OSStatus status = AudioConverterNew(&inputFormat, &_outputFormat, &_audioConverter);
  109. if (status != noErr) {
  110. _audioConverter = NULL;
  111. }
  112. }
  113. - (void)_fillMagicCookieForAudioFileID:(AudioFileID)inputFile
  114. {
  115. UInt32 cookieSize = 0;
  116. OSStatus status = AudioFileGetPropertyInfo(inputFile, kAudioFilePropertyMagicCookieData, &cookieSize, NULL);
  117. if (status == noErr && cookieSize > 0) {
  118. void *cookie = malloc(cookieSize);
  119. status = AudioFileGetProperty(inputFile, kAudioFilePropertyMagicCookieData, &cookieSize, cookie);
  120. if (status != noErr) {
  121. free(cookie);
  122. return;
  123. }
  124. status = AudioConverterSetProperty(_audioConverter, kAudioConverterDecompressionMagicCookie, cookieSize, cookie);
  125. free(cookie);
  126. if (status != noErr) {
  127. return;
  128. }
  129. }
  130. }
  131. - (BOOL)setUp
  132. {
  133. if (_decodingContextInitialized) {
  134. return YES;
  135. }
  136. AudioFileID inputFile = [_playbackItem fileID];
  137. if (inputFile == NULL) {
  138. return NO;
  139. }
  140. _decodingContext.inputFormat = [_playbackItem fileFormat];
  141. _decodingContext.outputFormat = _outputFormat;
  142. [self _fillMagicCookieForAudioFileID:inputFile];
  143. UInt32 size;
  144. OSStatus status;
  145. size = sizeof(_decodingContext.inputFormat);
  146. status = AudioConverterGetProperty(_audioConverter, kAudioConverterCurrentInputStreamDescription, &size, &_decodingContext.inputFormat);
  147. if (status != noErr) {
  148. return NO;
  149. }
  150. size = sizeof(_decodingContext.outputFormat);
  151. status = AudioConverterGetProperty(_audioConverter, kAudioConverterCurrentOutputStreamDescription, &size, &_decodingContext.outputFormat);
  152. if (status != noErr) {
  153. return NO;
  154. }
  155. AudioStreamBasicDescription baseFormat;
  156. UInt32 propertySize = sizeof(baseFormat);
  157. AudioFileGetProperty(inputFile, kAudioFilePropertyDataFormat, &propertySize, &baseFormat);
  158. double actualToBaseSampleRateRatio = 1.0;
  159. if (_decodingContext.inputFormat.mSampleRate != baseFormat.mSampleRate &&
  160. _decodingContext.inputFormat.mSampleRate != 0.0 &&
  161. baseFormat.mSampleRate != 0.0) {
  162. actualToBaseSampleRateRatio = _decodingContext.inputFormat.mSampleRate / baseFormat.mSampleRate;
  163. }
  164. double srcRatio = 1.0;
  165. if (_decodingContext.outputFormat.mSampleRate != 0.0 &&
  166. _decodingContext.inputFormat.mSampleRate != 0.0) {
  167. srcRatio = _decodingContext.outputFormat.mSampleRate / _decodingContext.inputFormat.mSampleRate;
  168. }
  169. _decodingContext.decodeValidFrames = 0;
  170. AudioFilePacketTableInfo srcPti;
  171. if (_decodingContext.inputFormat.mBitsPerChannel == 0) {
  172. size = sizeof(srcPti);
  173. status = AudioFileGetProperty(inputFile, kAudioFilePropertyPacketTableInfo, &size, &srcPti);
  174. if (status == noErr) {
  175. _decodingContext.decodeValidFrames = (SInt64)(actualToBaseSampleRateRatio * srcRatio * srcPti.mNumberValidFrames + 0.5);
  176. AudioConverterPrimeInfo primeInfo;
  177. primeInfo.leadingFrames = (UInt32)(srcPti.mPrimingFrames * actualToBaseSampleRateRatio + 0.5);
  178. primeInfo.trailingFrames = 0;
  179. status = AudioConverterSetProperty(_audioConverter, kAudioConverterPrimeInfo, sizeof(primeInfo), &primeInfo);
  180. if (status != noErr) {
  181. return NO;
  182. }
  183. }
  184. }
  185. _decodingContext.afio.afid = inputFile;
  186. _decodingContext.afio.srcBufferSize = (UInt32)_bufferSize;
  187. _decodingContext.afio.srcBuffer = malloc(_decodingContext.afio.srcBufferSize);
  188. _decodingContext.afio.pos = 0;
  189. _decodingContext.afio.srcFormat = _decodingContext.inputFormat;
  190. if (_decodingContext.inputFormat.mBytesPerPacket == 0) {
  191. size = sizeof(_decodingContext.afio.srcSizePerPacket);
  192. status = AudioFileGetProperty(inputFile, kAudioFilePropertyPacketSizeUpperBound, &size, &_decodingContext.afio.srcSizePerPacket);
  193. if (status != noErr) {
  194. free(_decodingContext.afio.srcBuffer);
  195. return NO;
  196. }
  197. _decodingContext.afio.numPacketsPerRead = _decodingContext.afio.srcBufferSize / _decodingContext.afio.srcSizePerPacket;
  198. _decodingContext.afio.pktDescs = (AudioStreamPacketDescription *)malloc(sizeof(AudioStreamPacketDescription) * _decodingContext.afio.numPacketsPerRead);
  199. }
  200. else {
  201. _decodingContext.afio.srcSizePerPacket = _decodingContext.inputFormat.mBytesPerPacket;
  202. _decodingContext.afio.numPacketsPerRead = _decodingContext.afio.srcBufferSize / _decodingContext.afio.srcSizePerPacket;
  203. _decodingContext.afio.pktDescs = NULL;
  204. }
  205. _decodingContext.outputPktDescs = NULL;
  206. UInt32 outputSizePerPacket = _decodingContext.outputFormat.mBytesPerPacket;
  207. _decodingContext.outputBufferSize = (UInt32)_bufferSize;
  208. _decodingContext.outputBuffer = malloc(_decodingContext.outputBufferSize);
  209. if (outputSizePerPacket == 0) {
  210. size = sizeof(outputSizePerPacket);
  211. status = AudioConverterGetProperty(_audioConverter, kAudioConverterPropertyMaximumOutputPacketSize, &size, &outputSizePerPacket);
  212. if (status != noErr) {
  213. free(_decodingContext.afio.srcBuffer);
  214. free(_decodingContext.outputBuffer);
  215. if (_decodingContext.afio.pktDescs != NULL) {
  216. free(_decodingContext.afio.pktDescs);
  217. }
  218. return NO;
  219. }
  220. _decodingContext.outputPktDescs = (AudioStreamPacketDescription *)malloc(sizeof(AudioStreamPacketDescription) * _decodingContext.outputBufferSize / outputSizePerPacket);
  221. }
  222. _decodingContext.numOutputPackets = _decodingContext.outputBufferSize / outputSizePerPacket;
  223. _decodingContext.outputPos = 0;
  224. pthread_mutex_init(&_decodingContext.mutex, NULL);
  225. _decodingContextInitialized = YES;
  226. return YES;
  227. }
  228. - (void)tearDown
  229. {
  230. if (!_decodingContextInitialized) {
  231. return;
  232. }
  233. free(_decodingContext.afio.srcBuffer);
  234. free(_decodingContext.outputBuffer);
  235. if (_decodingContext.afio.pktDescs != NULL) {
  236. free(_decodingContext.afio.pktDescs);
  237. }
  238. if (_decodingContext.outputPktDescs != NULL) {
  239. free(_decodingContext.outputPktDescs);
  240. }
  241. pthread_mutex_destroy(&_decodingContext.mutex);
  242. _decodingContextInitialized = NO;
  243. }
  244. static OSStatus decoder_data_proc(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPackets, AudioBufferList *ioData, AudioStreamPacketDescription **outDataPacketDescription, void *inUserData)
  245. {
  246. AudioFileIO *afio = (AudioFileIO *)inUserData;
  247. if (*ioNumberDataPackets > afio->numPacketsPerRead) {
  248. *ioNumberDataPackets = afio->numPacketsPerRead;
  249. }
  250. UInt32 outNumBytes;
  251. OSStatus status = AudioFileReadPackets(afio->afid, FALSE, &outNumBytes, afio->pktDescs, afio->pos, ioNumberDataPackets, afio->srcBuffer);
  252. if (status != noErr) {
  253. return status;
  254. }
  255. afio->pos += *ioNumberDataPackets;
  256. ioData->mBuffers[0].mData = afio->srcBuffer;
  257. ioData->mBuffers[0].mDataByteSize = outNumBytes;
  258. ioData->mBuffers[0].mNumberChannels = afio->srcFormat.mChannelsPerFrame;
  259. if (outDataPacketDescription != NULL) {
  260. *outDataPacketDescription = afio->pktDescs;
  261. }
  262. return noErr;
  263. }
  264. - (DOUAudioDecoderStatus)decodeOnce
  265. {
  266. if (!_decodingContextInitialized) {
  267. return DOUAudioDecoderFailed;
  268. }
  269. pthread_mutex_lock(&_decodingContext.mutex);
  270. DOUAudioFileProvider *provider = [_playbackItem fileProvider];
  271. if ([provider isFailed]) {
  272. [_lpcm setEnd:YES];
  273. pthread_mutex_unlock(&_decodingContext.mutex);
  274. return DOUAudioDecoderFailed;
  275. }
  276. if (![provider isFinished]) {
  277. NSUInteger dataOffset = [_playbackItem dataOffset];
  278. NSUInteger expectedDataLength = [provider expectedLength];
  279. NSInteger receivedDataLength = (NSInteger)([provider receivedLength] - dataOffset);
  280. SInt64 packetNumber = _decodingContext.afio.pos + _decodingContext.afio.numPacketsPerRead;
  281. SInt64 packetDataOffset = packetNumber * _decodingContext.afio.srcSizePerPacket;
  282. SInt64 bytesPerPacket = _decodingContext.afio.srcSizePerPacket;
  283. SInt64 bytesPerRead = bytesPerPacket * _decodingContext.afio.numPacketsPerRead;
  284. SInt64 framesPerPacket = _decodingContext.inputFormat.mFramesPerPacket;
  285. double intervalPerPacket = 1000.0 / _decodingContext.inputFormat.mSampleRate * framesPerPacket;
  286. double intervalPerRead = intervalPerPacket / bytesPerPacket * bytesPerRead;
  287. double downloadTime = 1000.0 * (bytesPerRead - (receivedDataLength - packetDataOffset)) / [provider downloadSpeed];
  288. SInt64 bytesRemaining = (SInt64)(expectedDataLength - (NSUInteger)receivedDataLength);
  289. if (receivedDataLength < packetDataOffset ||
  290. (bytesRemaining > 0 &&
  291. downloadTime > intervalPerRead)) {
  292. pthread_mutex_unlock(&_decodingContext.mutex);
  293. return DOUAudioDecoderWaiting;
  294. }
  295. }
  296. AudioBufferList fillBufList;
  297. fillBufList.mNumberBuffers = 1;
  298. fillBufList.mBuffers[0].mNumberChannels = _decodingContext.inputFormat.mChannelsPerFrame;
  299. fillBufList.mBuffers[0].mDataByteSize = _decodingContext.outputBufferSize;
  300. fillBufList.mBuffers[0].mData = _decodingContext.outputBuffer;
  301. OSStatus status;
  302. UInt32 ioOutputDataPackets = _decodingContext.numOutputPackets;
  303. status = AudioConverterFillComplexBuffer(_audioConverter, decoder_data_proc, &_decodingContext.afio, &ioOutputDataPackets, &fillBufList, _decodingContext.outputPktDescs);
  304. if (status != noErr) {
  305. pthread_mutex_unlock(&_decodingContext.mutex);
  306. return DOUAudioDecoderFailed;
  307. }
  308. if (ioOutputDataPackets == 0) {
  309. [_lpcm setEnd:YES];
  310. pthread_mutex_unlock(&_decodingContext.mutex);
  311. return DOUAudioDecoderEndEncountered;
  312. }
  313. SInt64 frame1 = _decodingContext.outputPos + ioOutputDataPackets;
  314. if (_decodingContext.decodeValidFrames != 0 &&
  315. frame1 > _decodingContext.decodeValidFrames) {
  316. SInt64 framesToTrim64 = frame1 - _decodingContext.decodeValidFrames;
  317. UInt32 framesToTrim = (framesToTrim64 > ioOutputDataPackets) ? ioOutputDataPackets : (UInt32)framesToTrim64;
  318. int bytesToTrim = (int)(framesToTrim * _decodingContext.outputFormat.mBytesPerFrame);
  319. fillBufList.mBuffers[0].mDataByteSize -= (unsigned long)bytesToTrim;
  320. ioOutputDataPackets -= framesToTrim;
  321. if (ioOutputDataPackets == 0) {
  322. [_lpcm setEnd:YES];
  323. pthread_mutex_unlock(&_decodingContext.mutex);
  324. return DOUAudioDecoderEndEncountered;
  325. }
  326. }
  327. UInt32 inNumBytes = fillBufList.mBuffers[0].mDataByteSize;
  328. [_lpcm writeBytes:_decodingContext.outputBuffer length:inNumBytes];
  329. _decodingContext.outputPos += ioOutputDataPackets;
  330. pthread_mutex_unlock(&_decodingContext.mutex);
  331. return DOUAudioDecoderSucceeded;
  332. }
  333. - (void)seekToTime:(NSUInteger)milliseconds
  334. {
  335. if (!_decodingContextInitialized) {
  336. return;
  337. }
  338. pthread_mutex_lock(&_decodingContext.mutex);
  339. double frames = (double)milliseconds * _decodingContext.inputFormat.mSampleRate / 1000.0;
  340. double packets = frames / _decodingContext.inputFormat.mFramesPerPacket;
  341. SInt64 packetNumebr = (SInt64)lrint(floor(packets));
  342. _decodingContext.afio.pos = packetNumebr;
  343. _decodingContext.outputPos = packetNumebr * _decodingContext.inputFormat.mFramesPerPacket / _decodingContext.outputFormat.mFramesPerPacket;
  344. pthread_mutex_unlock(&_decodingContext.mutex);
  345. }
  346. @end