Objective-c - How to serialize audio file into small packets that can be played?

后端 未结 3 765
生来不讨喜
生来不讨喜 2020-12-14 04:56

So, I would like to get a sound file and convert it in packets, and send it to another computer. I would like that the other computer be able to play the packets as they arr

3条回答
  •  [愿得一人]
    2020-12-14 05:56

    Here is simplest class to play files with AQ Note that you can play it from any point (just set currentPacketNumber)

    #import 
    #import 
    
    @interface AudioFile : NSObject {
        AudioFileID                     fileID;     // the identifier for the audio file to play
        AudioStreamBasicDescription     format;
        UInt64                          packetsCount;           
        UInt32                          maxPacketSize;  
    }
    
    @property (readwrite)           AudioFileID                 fileID;
    @property (readwrite)           UInt64                      packetsCount;
    @property (readwrite)           UInt32                      maxPacketSize;
    
    - (id) initWithURL: (CFURLRef) url;
    - (AudioStreamBasicDescription *)audioFormatRef;
    
    @end
    
    
    //  AudioFile.m
    
    #import "AudioFile.h"
    
    
    @implementation AudioFile
    
    @synthesize fileID;
    @synthesize format;
    @synthesize maxPacketSize;
    @synthesize packetsCount;
    
    - (id)initWithURL:(CFURLRef)url{
        if (self = [super init]){       
            AudioFileOpenURL(
                             url,
                             0x01, //fsRdPerm, read only
                             0, //no hint
                             &fileID
                             );
    
            UInt32 sizeOfPlaybackFormatASBDStruct = sizeof format;
            AudioFileGetProperty (
                                  fileID, 
                                  kAudioFilePropertyDataFormat,
                                  &sizeOfPlaybackFormatASBDStruct,
                                  &format
                                  );
    
            UInt32 propertySize = sizeof (maxPacketSize);
    
            AudioFileGetProperty (
                                  fileID, 
                                  kAudioFilePropertyMaximumPacketSize,
                                  &propertySize,
                                  &maxPacketSize
                                  );
    
            propertySize = sizeof(packetsCount);
            AudioFileGetProperty(fileID, kAudioFilePropertyAudioDataPacketCount, &propertySize, &packetsCount);
        }
        return self;
    } 
    
    -(AudioStreamBasicDescription *)audioFormatRef{
        return &format;
    }
    
    - (void) dealloc {
        AudioFileClose(fileID);
        [super dealloc];
    }
    
    
    
    //  AQPlayer.h
    
    #import 
    #import "AudioFile.h"
    
    #define AUDIOBUFFERS_NUMBER     3
    #define MAX_PACKET_COUNT    4096
    
    @interface AQPlayer : NSObject {
    @public
        AudioQueueRef                   queue;
        AudioQueueBufferRef             buffers[AUDIOBUFFERS_NUMBER];
        NSInteger                       bufferByteSize;
        AudioStreamPacketDescription    packetDescriptions[MAX_PACKET_COUNT];
    
        AudioFile * audioFile;
        SInt64  currentPacketNumber;
        UInt32  numPacketsToRead;
    }
    
    @property (nonatomic)               SInt64          currentPacketNumber;
    @property (nonatomic, retain)       AudioFile       * audioFile;
    
    -(id)initWithFile:(NSString *)file;
    -(NSInteger)fillBuffer:(AudioQueueBufferRef)buffer;
    -(void)play;
    
    @end 
    
    //  AQPlayer.m
    
    #import "AQPlayer.h"
    
    static void AQOutputCallback(void * inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) {
        AQPlayer * aqp = (AQPlayer *)inUserData;
        [aqp fillBuffer:(AudioQueueBufferRef)inBuffer];
    }
    
    @implementation AQPlayer
    
    @synthesize currentPacketNumber;
    @synthesize audioFile;
    
    -(id)initWithFile:(NSString *)file{
        if ([self init]){
            audioFile = [[AudioFile alloc] initWithURL:[NSURL fileURLWithPath:file]];
            currentPacketNumber = 0;
            AudioQueueNewOutput ([audioFile audioFormatRef], AQOutputCallback, self, CFRunLoopGetCurrent (), kCFRunLoopCommonModes, 0, &queue);
            bufferByteSize = 4096;
            if (bufferByteSize < audioFile.maxPacketSize) bufferByteSize = audioFile.maxPacketSize; 
            numPacketsToRead = bufferByteSize/audioFile.maxPacketSize;
            for(int i=0; imBytesPerPacket == 0 ? YES : NO;
        AudioFileReadPackets(
                             audioFile.fileID,
                             NO,
                             &numBytes,
                             isVBR ? packetDescriptions : 0,
                             currentPacketNumber,
                             &numPackets, 
                             buffer->mAudioData
                             );
    
        if (numPackets > 0) {
            buffer->mAudioDataByteSize = numBytes;      
            AudioQueueEnqueueBuffer (
                                     queue,
                                     buffer,
                                     isVBR ? numPackets : 0,
                                     isVBR ? packetDescriptions : 0
                                     );
    
    
        } 
        else{
            // end of present data, check if all packets are played
            // if yes, stop play and dispose queue
            // if no, pause queue till new data arrive then start it again
        }
        return  numPackets;
    }
    

提交回复
热议问题