spe*_*tak 18 iphone objective-c stream ipad ios
我从设备iTunes库中获取一首歌并将其推入AVAsset:
- (void)mediaPicker: (MPMediaPickerController *)mediaPicker didPickMediaItems:(MPMediaItemCollection *)mediaItemCollection
{
NSArray *arr = mediaItemCollection.items;
MPMediaItem *song = [arr objectAtIndex:0];
NSData *songData = [NSData dataWithContentsOfURL:[song valueForProperty:MPMediaItemPropertyAssetURL]];
}
Run Code Online (Sandbox Code Playgroud)
然后我有这个Game Center方法来接收数据:
- (void)match:(GKMatch *)match didReceiveData:(NSData *)data fromPlayer:(NSString *)playerID
Run Code Online (Sandbox Code Playgroud)
我很难找到如何通过GameCenter发送这个AVAsset然后让它在接收设备上播放.
我读过:http: //developer.apple.com/library/ios/#documentation/MusicAudio/Reference/AudioStreamReference/Reference/reference.html#//apple_ref/doc/uid/TP40006162
我迷失了.信息超载.
我已经实现了Cocoa With Love的音频流代码,但我无法弄清楚如何通过GameCenter获取我收到的NSData并将其推送到他的代码中. http://cocoawithlove.com/2008/09/streaming-and-playing-live-mp3-stream.html
有人可以帮我解决这个问题吗?因此,我需要帮助的部分只是简单地将歌曲数据分解成数据包(或者它可以工作),然后迭代这些数据包并通过游戏套件发送它,然后解析它在接收设备上传入的数据作为播放它它进来了.
Max*_*eod 31
您需要查看的API是"音频队列服务".
是的,这里是您需要做的基本概述.
播放音频时,您可以设置队列或服务.该队列将要求一些音频数据.然后,当它播放了所有这些后,它会要求更多.这一直持续到您停止队列,或者没有更多数据要播放.
iOS中的两个主要低级API是Audio Unit和Audio Queue.从较低的层面来说,我的意思是一个API,比说"只是回放这个mp3"或其他什么更加细致.
我的经验是音频单元的延迟较低,但音频队列更适合流式传输音频.所以,我认为后者是一个更好的选择.
您需要做的一件事就是缓冲.这意味着充分加载数据,以便播放中没有间隙.您可能希望通过最初加载大量数据来处理此问题.那你就是在前面.您将在内存中拥有足够大的缓冲区,同时在后台线程上接收更多数据.
我建议密切研究的样本项目是SpeakHere.特别是看看课程SpeakHereController.mm和AQPlayer.mm.
控制器处理启动和停止等操作AQPlayer.AQPlayer代表一个AudioQueue.仔细看看AQPlayer::AQBufferCallback.这是队列需要更多数据时调用的回调方法.
您需要确保队列数据的设置以及您收到的数据格式完全匹配.检查诸如通道数量(单声道或立体声?),帧数,整数或浮点数和采样率等内容.如果任何事情不匹配,你会在EXC_BAD_ACCESS你通过各自的缓冲区时遇到错误,或者你会得到白噪声,或者 - 在采样率错误的情况下 - 听起来减慢或加速的音频.
请注意,SpeakHere运行两个音频队列; 一个用于录制,一个用于播放.所有音频内容都使用数据缓冲区.所以你总是将循环指针传递给缓冲区.因此,例如在播放期间,您将说一个具有20秒音频的内存缓冲区.也许每秒你的回调都会被队列调用,基本上就是说"请给我另一秒钟的数据".您可以将其视为一个回放头,它可以移动您的数据,请求更多信息.
让我们更详细地看一下这个.与SpeakHere不同,您将使用内存缓冲区而不是将音频写入临时文件.
请注意,如果您正在处理大量数据,那么在iOS设备上,您将别无选择,只能在磁盘上保留大部分数据.特别是如果用户可以重放音频,倒回音频等,你需要把它放在某个地方!
无论如何,假设AQPlayer它将从内存中读取,我们需要如下改变它.
首先,在某处保存数据,在AQPlayer.h:
void SetAudioBuffer(float *inAudioBuffer) { mMyAudioBuffer = inAudioBuffer; }
Run Code Online (Sandbox Code Playgroud)
您已经在NSData对象中拥有该数据,因此您只需传入从调用返回的指针即可[myData bytes].
是什么将这些数据提供给音频队列?这是设置的回调方法AQPlayer:
void AQPlayer::AQBufferCallback(void * inUserData,
AudioQueueRef inAQ,
AudioQueueBufferRef inCompleteAQBuffer)
Run Code Online (Sandbox Code Playgroud)
我们用于将部分数据添加到音频队列的方法是AudioQueueEnqueueBuffer:
AudioQueueEnqueueBuffer(inAQ, inCompleteAQBuffer, 0, NULL);
Run Code Online (Sandbox Code Playgroud)
inAQ是我们的回调接收到的队列的引用.
inCompleteAQBuffer是指向音频队列缓冲区的指针.
那么如何通过调用bytesNSData对象上的方法将数据(即通过调用NSData对象上的方法返回的指针)放入音频队列缓冲区inCompleteAQBuffer?
使用memcpy:
memcpy(inCompleteAQBuffer->mAudioData, THIS->mMyAudioBuffer + (THIS->mMyPlayBufferPosition / sizeof(float)), numBytesToCopy);
Run Code Online (Sandbox Code Playgroud)
您还需要设置缓冲区大小:
inCompleteAQBuffer->mAudioDataByteSize = numBytesToCopy;
Run Code Online (Sandbox Code Playgroud)
numBytesToCopy总是会是一样的,除非你刚要用完数据.例如,如果您的缓冲区是2秒钟的音频数据,并且您有9秒钟的播放时间,那么对于前四个回调,您将获得2秒的值.对于最终回调,您只剩下1秒的数据.numBytesToCopy必须反映这一点.
// Calculate how many bytes are remaining? It could be less than a normal buffer
// size. For example, if the buffer size is 0.5 seconds and recording stopped
// halfway through that. In which case, we copy across only the recorded bytes
// and we don't enqueue any more buffers.
SInt64 numRemainingBytes = THIS->mPlayBufferEndPosition - THIS->mPlayBufferPosition;
SInt64 numBytesToCopy = numRemainingBytes < THIS->mBufferByteSize ? numRemainingBytes : THIS->mBufferByteSize;
Run Code Online (Sandbox Code Playgroud)
最后,我们推进了播放头.在我们的回调中,我们已经为队列提供了一些数据.下次我们收到回调会发生什么?我们不想再提供相同的数据.除非你做一些时髦的dj循环!
所以我们推进了头部,它基本上只是指向音频缓冲区的指针.指针像记录中的针一样在缓冲区中移动:
SELF->mPlayBufferPosition += numBytesToCopy;
Run Code Online (Sandbox Code Playgroud)
而已!还有一些其他逻辑,但你可以通过研究SpeakHere中的完整回调方法来实现.
我必须强调几点.首先,不要只复制并粘贴我上面的代码.绝对要确保你明白自己在做什么.毫无疑问,你会遇到问题,你需要了解发生了什么.
其次,确保音频格式相同,甚至更好地理解音频格式.录音中的音频队列服务编程指南中对此进行了介绍.查看清单2-8指定音频队列的音频数据格式.
了解您拥有最原始的数据单元(整数或浮点数)至关重要.单声道或立体声,帧中有一个或两个声道.这定义了该帧中有多少整数或浮点数.然后你有每个数据包的帧(可能是1).您的采样率决定了您每秒有多少数据包.
这些都包含在文档中.只要确保一切都匹配,否则你会有一些非常奇怪的声音!
祝好运!