Objective-C的 - 如何序列化的音频文件转换成小的数据包可以播放? [英] Objective-c - How to serialize audio file into small packets that can be played?

查看:364
本文介绍了Objective-C的 - 如何序列化的音频文件转换成小的数据包可以播放?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以,我想获得一个声音文件,并将其转换的数据包,并将其发送到另一台计算机。我想,其他计算机能够到达时播放的数据包。

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 arrive.

我使用AVAudioPlayer尝试玩这个数据包,但我找不到序列化对等方1的对等方2可以播放数据的正确方法。

I am using AVAudioPlayer to try to play this packets, but I couldn't find a proper way to serialize the data on the peer1 that the peer2 can play.

的方案是,peer1的有一个音频文件,在许多小的数据包分割音频文件,把它们放在一个的NSData并将它们发送到对等方2。同行2个接收数据包并播放之一,因为他们到达。

The scenario is, peer1 has a audio file, split the audio file in many small packets, put them on a NSData and send them to peer2. Peer 2 receive the packets and play one by one, as they arrive.

有谁知道了如何做到这一点?或者即使它是可能的?

Does anyone have know how to do this? or even if it is possible?

编辑:

这一块的一些code来说明我想达到的目标。

Here it is some piece of code to illustrate what I would like to achieve.


// This code is part of the peer1, the one who sends the data
- (void)sendData
{
    int packetId = 0;
    NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:@"myAudioFile" ofType:@"wav"];

    NSData *soundData = [[NSData alloc] initWithContentsOfFile:soundFilePath];
    NSMutableArray *arraySoundData = [[NSMutableArray alloc] init];

    // Spliting the audio in 2 pieces
    // This is only an illustration
    // The idea is to split the data into multiple pieces
    // dependin on the size of the file to be sent
    NSRange soundRange;
    soundRange.length = [soundData length]/2;
    soundRange.location = 0;
    [arraySoundData addObject:[soundData subdataWithRange:soundRange]];
    soundRange.length = [soundData length]/2;
    soundRange.location = [soundData length]/2;
    [arraySoundData addObject:[soundData subdataWithRange:soundRange]];

    for (int i=0; i<[arraySoundData count]; i++)
    {
        NSData *soundPacket = [arraySoundData objectAtIndex:i];

        if(soundPacket == nil)
        {
            NSLog(@"soundData is nil");
            return;
        }       

        NSMutableData* message = [[NSMutableData alloc] init];
        NSKeyedArchiver* archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:message];
        [archiver encodeInt:packetId++ forKey:PACKET_ID];
        [archiver encodeObject:soundPacket forKey:PACKET_SOUND_DATA];
        [archiver finishEncoding];      

        NSError* error = nil;
        [connectionManager sendMessage:message error:&error];
        if (error) NSLog (@"send greeting failed: %@" , [error localizedDescription]);

        [message release];
        [archiver release];
    }

    [soundData release];
    [arraySoundData release];
}


// This is the code on peer2 that would receive and play the piece of audio on each packet

- (void) receiveData:(NSData *)data
{

    NSKeyedUnarchiver* unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];

    if ([unarchiver containsValueForKey:PACKET_ID])
        NSLog(@"DECODED PACKET_ID: %i", [unarchiver decodeIntForKey:PACKET_ID]);

    if ([unarchiver containsValueForKey:PACKET_SOUND_DATA])
    {
        NSLog(@"DECODED sound");
        NSData *sound = (NSData *)[unarchiver decodeObjectForKey:PACKET_SOUND_DATA];

        if (sound == nil)
        {
            NSLog(@"sound is nil!");

        }
        else
        {
            NSLog(@"sound is not nil!");

            AVAudioPlayer *audioPlayer = [AVAudioPlayer alloc];

            if ([audioPlayer initWithData:sound error:nil])
            {
                [audioPlayer prepareToPlay];
                [audioPlayer play];
            } else {
                [audioPlayer release];
                NSLog(@"Player couldn't load data");
            }   
        }
    }

    [unarchiver release];
}

所以,这里就是我想实现...所以,我真正需要知道的是如何创建的数据包,因此对等方2可以播放音频。

So, here is what I am trying to achieve...so, what I really need to know is how to create the packets, so peer2 can play the audio.

这将是一种流媒体。是的,现在我不担心数据包接收或播放顺序......我只需要得到声音切片,并将它们能够发挥每片,每一片,而不需要等待整个文件是通过对等方2好评。

It would be a kind of streaming. Yes, for now I am not worried about the order that the packet are received or played...I only need to get the sound sliced and them be able to play each piece, each slice, without need to wait for the whole file be received by peer2.

谢谢!

推荐答案

看来你解决了一个错误的任务,因为 AVAudioPlayer 能仅发挥整体的AudioFile。你应该使用音频队列服务从 AudioToolbox 框架相反,对数据包逐包基础上播放音频。其实你大可不必audiofile的分成后的实际声音数据包,您可以在自己的例子中使用的任何数据块像上面,但你应该使用的 AUDIOFILE服务音频文件流读取接收数据chuncks服务功能(从 AudioToolbox )和饲料他们audioqueue缓冲区。

It seems you are solving wrong task, because AVAudioPlayer capable play only whole audiofile. You should use Audio Queue Service from AudioToolbox framework instead, to play audio on packet-by-packet basis. In fact you need not divide audiofile into real sound packets, you can use any data block like in your own example above, but then you should read received data chuncks using Audiofile Service or Audio File Stream Services functions (from AudioToolbox) and feed them to audioqueue buffers.

如果你仍然想的AudioFile分成声音数据包,可以方便的与AUDIOFILE服务功能做到这一点。 AUDIOFILE包括头,其中它的属性,如数据包数量,采样率,声道数等存储和原始声音数据。

If you nevertheless want to divide audiofile into sound packets, you can easily do it with Audiofile Service functions. Audiofile consist of header where its properties like number of packets, samplerate, number of channels etc. are stored, and raw sound data.

使用 AudioFileOpenURL 打开的AudioFile并采取与 AudioFileGetProperty 函数的所有属性。 Basicaly你只需要kAudioFilePropertyDataFormat和kAudioFilePropertyAudioDataPacketCount属性:

Use AudioFileOpenURL to open audiofile and take all its properties with AudioFileGetProperty function. Basicaly you need only kAudioFilePropertyDataFormat and kAudioFilePropertyAudioDataPacketCount properties:

AudioFileID  fileID;    // the identifier for the audio file
CFURLRef     fileURL = ...; // file URL
AudioStreamBasicDescription format; // structure containing audio header info
    UInt64  packetsCount;

AudioFileOpenURL(fileURL, 
    0x01, //fsRdPerm,                       // read only
    0, //no hint
    &fileID
);

UInt32 sizeOfPlaybackFormatASBDStruct = sizeof format;
AudioFileGetProperty (
    fileID, 
    kAudioFilePropertyDataFormat,
    &sizeOfPlaybackFormatASBDStruct,
    &format
);

propertySize = sizeof(packetsCount);
AudioFileGetProperty(fileID, kAudioFilePropertyAudioDataPacketCount, &propertySize, &packetsCount);

那么你可以采取audiopackets数据与任何范围:

Then you can take any range of audiopackets data with:

   OSStatus AudioFileReadPackets (
       AudioFileID                  inAudioFile,
       Boolean                      inUseCache,
       UInt32                       *outNumBytes,
       AudioStreamPacketDescription *outPacketDescriptions,
       SInt64                       inStartingPacket,
       UInt32                       *ioNumPackets,
       void                         *outBuffer
    );

这篇关于Objective-C的 - 如何序列化的音频文件转换成小的数据包可以播放?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆