Objective-c - 如何将音频文件序列化成可以播放的小数据包?
所以,我想获取一个声音文件并将其转换为数据包,然后将其发送到另一台计算机。我希望另一台计算机能够在数据包到达时播放它们。
我正在使用 AVAudioPlayer 尝试播放此数据包,但我找不到正确的方法来序列化对等体 1 上对等体 2 可以播放的数据。
场景是,peer1 有一个音频文件,将音频文件分割成许多小数据包,将它们放在 NSData 上并发送给peer2。对等点 2 接收数据包并在数据包到达时一一播放。
有谁知道该怎么做?或者即使有可能?
编辑:
这是一些代码来说明我想要实现的目标。
// 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];
}
所以,这就是我想要实现的目标......所以,我真正需要知道的是如何创建数据包,以便peer2可以播放音频。
这将是一种流媒体。是的,现在我不担心数据包接收或播放的顺序...我只需要对声音进行切片,他们就能够播放每个片段,每个片段,而不需要等待整个文件被处理由peer2收到。
谢谢!
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.
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.
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?
EDIT:
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];
}
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.
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.
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这是使用 AQ 播放文件的最简单的类
请注意,您可以从任意点播放(只需设置 currentPacketNumber)
Here is simplest class to play files with AQ
Note that you can play it from any point (just set currentPacketNumber)
看来您正在解决错误的任务,因为 AVAudioPlayer 只能播放整个音频文件。您应该使用 AudioToolbox 框架中的音频队列服务,以逐个数据包的方式播放音频。事实上,您不需要将音频文件分成真正的声音数据包,您可以使用任何数据块,就像上面您自己的示例一样,但是您应该使用音频文件服务或音频文件流读取接收到的数据块服务函数(来自AudioToolbox)并将它们提供给音频队列缓冲区。
如果您仍然想将音频文件分成声音数据包,您可以使用音频文件服务功能轻松完成。音频文件由存储数据包数量、采样率、通道数量等属性的标头和原始声音数据组成。
使用AudioFileOpenURL打开音频文件并使用AudioFileGetProperty函数获取其所有属性。基本上,您只需要 kAudioFilePropertyDataFormat 和 kAudioFilePropertyAudioDataPacketCount 属性:
然后您可以使用以下命令获取任何范围的音频数据包数据:
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.
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.
Use AudioFileOpenURL to open audiofile and take all its properties with AudioFileGetProperty function. Basicaly you need only kAudioFilePropertyDataFormat and kAudioFilePropertyAudioDataPacketCount properties:
Then you can take any range of audiopackets data with:
Apple 已经编写了可以做到这一点的东西:AUNetSend 和 AUNetReceive。 AUNetSend 是一个效果 AudioUnit,它将音频发送到另一台计算机上的 AUNetReceive AudioUnit。
不幸的是,这些 AU 在 iPhone 上不可用。
Apple already has written something that can do this: AUNetSend and AUNetReceive. AUNetSend is an effect AudioUnit that sends audio to an AUNetReceive AudioUnit on another computer.
Unfortunately these AUs are not available on the iPhone, though.