Ios4 有没有办法用Matt Gallagher的音频拖缆录制音频流?
我使用流媒体广播电台。但是如何录制音频呢?有没有办法将下载的数据包保存到iPhone的documents文件夹中的音频文件中Ios4 有没有办法用Matt Gallagher的音频拖缆录制音频流?,ios4,core-audio,audio-streaming,audio-recording,Ios4,Core Audio,Audio Streaming,Audio Recording,我使用流媒体广播电台。但是如何录制音频呢?有没有办法将下载的数据包保存到iPhone的documents文件夹中的音频文件中 谢谢是的,有,我已经做了。我的问题是能否在其他地方询问的相同拖缆中播放它。它将在iOS中使用标准AVAudioPlayer进行回放。但是,这将通过在拖缆代码中写入数据来将数据保存到文件中 此示例缺少一些错误检查,但将为您提供主要内容 首先,从主线程调用开始和停止录制。当有人按record时,这会出现在我的viewController中: //---------------
谢谢是的,有,我已经做了。我的问题是能否在其他地方询问的相同拖缆中播放它。它将在iOS中使用标准AVAudioPlayer进行回放。但是,这将通过在拖缆代码中写入数据来将数据保存到文件中 此示例缺少一些错误检查,但将为您提供主要内容 首先,从主线程调用开始和停止录制。当有人按record时,这会出现在我的viewController中:
//---------------------------------------------------------
// Record button was pressed (toggle on/off)
// writes a file to the documents directory using date and time for the name
//---------------------------------------------------------
-(IBAction)recordButton:(id)sender {
// only start if the streamer is playing (self.streamer is my streamer instance)
if ([self.streamer isPlaying]) {
NSDate *currentDateTime = [NSDate date]; // get current date and time
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setDateFormat:@"EEEE MMMM d YYYY 'at' HH:mm:ss"];
NSString *dateString = [dateFormatter stringFromDate:currentDateTime];
self.isRecording = !self.isRecording; // toggle recording state BOOL
if (self.isRecording)
{
// start recording here
// change the record button to show it is recording - this is an IBOutlet
[self.recordButtonImage setImage:[UIImage imageNamed:@"Record2.png"] forState:0];
// call AudioStreamer to start recording. It returns the file pointer back
//
self.recordFilePath = [self.streamer recordStream:TRUE fileName:dateString]; // start file stream and get file pointer
} else
{
//stop recording here
// change the button back
[self.recordButtonImage setImage:[UIImage imageNamed:@"Record.png"] forState:0];
// call streamer code, stop the recording. Also returns the file path again.
self.recordFilePath = [self.streamer recordStream:FALSE fileName:nil]; // stop stream and get file pointer
// add to "recorded files" for selecting a recorderd file later.
// first, add channel, date, time
dateString = [NSString stringWithFormat:@"%@ Recorded on %@",self.model.stationName, dateString]; // used to identify the item in a list laster
// the dictionary will be used to hold the data on this recording for display elsewhere
NSDictionary *row1 = [[[NSDictionary alloc] initWithObjectsAndKeys: self.recordFilePath, @"path", dateString, @"dateTime", nil] autorelease];
// save the stream info in an array of recorded Streams
if (self.model.recordedStreamsArray == nil) {
self.model.recordedStreamsArray = [[NSMutableArray alloc] init]// init the array
}
[self.model.recordedStreamsArray addObject:row1]; // dict for this recording
}
}
}
现在,在AudioStreamer.m中,我需要处理上面的记录设置调用
- (NSString*)recordStream:(BOOL)record fileName:(NSString *)fileName
{
// this will start/stop recording, and return the file pointer
if (record) {
if (state == AS_PLAYING)
{
// now open a file to save the data into
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
// will call this an mp3 file for now (this may need to change)
NSMutableString *temp = [NSMutableString stringWithString:[documentsDirectory stringByAppendingFormat:@"/%@.mp3",fileName]];
// remove the ':' in the time string, and create a file name w/ time & date
[temp replaceOccurrencesOfString:@":" withString:@"" options:NSLiteralSearch range:NSMakeRange(0, [temp length])];
self.filePath = temp; // file name is date time generated.
NSLog(@"Stream Save File Open = %@", self.filePath);
// open the recording file stream output
self.fileStream = [NSOutputStream outputStreamToFileAtPath:self.filePath append:NO];
[self.fileStream open];
NSLog(@"recording to %@", self.fileStream);
self.isRecording = TRUE;
return (self.filePath); // if started, send back the file path
}
return (nil); // if not started, return nil for error checking
} else {
// save the stream here to a file.
// we are done, close the stream.
if (self.fileStream != nil) {
[self.fileStream close];
self.fileStream = nil;
}
NSLog(@"stop recording");
self.isRecording = FALSE;
return (self.filePath); // when stopping, return nil
}
}
最后,我们需要修改拖缆的数据部分以实际保存字节。您需要修改方法中的流代码:-voidHandlerReadFromStream:cfReadStreamRefStreamVentType:cfStreamVentTypeEventType
在该方法中向下滚动,直到找到:
@synchronized(self)
{
if ([self isFinishing] || !CFReadStreamHasBytesAvailable(stream))
{
return;
}
//
// Read the bytes from the stream
//
length = CFReadStreamRead(stream, bytes, kAQDefaultBufSize);
if (length == -1)
{
[self failWithErrorCode:AS_AUDIO_DATA_NOT_FOUND];
return;
}
在length=行之后添加以下代码:
//
// if recording, save the raw data to a file
//
if(self.isRecording && length != 0){
//
// write the data to a file
//
NSInteger bytesWritten;
NSInteger bytesWrittenSoFar;
bytesWrittenSoFar = 0;
do {
bytesWritten = [self.fileStream write:&bytes[bytesWrittenSoFar] maxLength:length - bytesWrittenSoFar];
NSLog(@"bytesWritten = %i",bytesWritten);
if (bytesWritten == -1) {
[self.fileStream close];
self.fileStream = nil;
NSLog(@"File write error");
break;
} else {
bytesWrittenSoFar += bytesWritten;
}
} while (bytesWrittenSoFar != length);
}
以下是.h声明:
添加到AudioStreamer.h的接口
// for recording and saving a stream
NSString* filePath;
NSOutputStream* fileStream;
BOOL isRecording;
BOOL isPlayingFile;
在视图控制器中,您需要:
@property(nonatomic, assign) IBOutlet UIButton* recordButtonImage;
@property(nonatomic, assign) BOOL isRecording;
@property (nonatomic, copy) NSString* recordFilePath;
希望这对别人有帮助。如果有问题,请告诉我,并且总是很高兴听到有人能够改进这一点
另外,有人问到self.model.xxx model是我创建的一个数据对象,它允许我轻松地传递由多个对象使用的数据,也可以由多个对象修改。我知道,全球数据是一种糟糕的形式,但有时只是让它更容易访问。调用时,我将数据模型传递给每个新对象。我在模型中保存了一组频道、歌曲名称、艺术家名称和其他与流相关的数据。我还将希望通过启动保存的任何数据(如设置)放在这里,并在每次更改持久数据时将此数据模型写入文件。在本例中,您可以将数据保存在本地。如果您需要有关模型传递的帮助,请告诉我。好的,下面是我如何播放录制的文件。播放文件时,站点URL包含文件的路径。self.model.playRecordedSong包含一个时间值,表示我要在流中播放多少秒。我有一本歌曲名称和时间索引的字典,这样我就可以在任何歌曲开始时跳入录制的流中。使用0从开头开始
NSError *error;
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:self.model.stationURL, [[NSBundle mainBundle] resourcePath]]];
// get the file URL and then create an audio player if we don't already have one.
if (audioPlayer == nil) {
// set the seconds count to the proper start point (0, or some time into the stream)
// this will be 0 for start of stream, or some value passed back if they picked a song.
self.recordPlaySecondsCount = self.model.playRecordedSong;
//create a new player
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
// set self so we can catch the end of file.
[audioPlayer setDelegate: self];
// audio player needs an NSTimeInterval. Get it from the seconds start point.
NSTimeInterval interval = self.model.playRecordedSong;
// seek to the proper place in file.
audioPlayer.currentTime = interval;
}
audioPlayer.numberOfLoops = 0; // do not repeat
if (audioPlayer == nil)
NSLog(@"AVAudiolayer error: %@", error);
// I need to do more on the error of no player
else {
[audioPlayer play];
}
我希望这有助于您播放录制的文件。试试这门课程,它提供了所有无线流媒体录制播放的完整解决方案
您想将流保存到本地磁盘?但问题的标题似乎是录制音频。是的,录制音频流的意思是将流保存到本地磁盘。就我在iPhone上的情况而言,你有解决方案吗?@FFraenz你有办法吗?我也需要类似的东西…不,直到现在我还不知道..@FFraenz如果你得到一个解决方案,那么请与我分享…如果我得到了,我会的…所以现在我真正的问题是如何在同一个程序中播放这段录音。我尝试用URL文件调用打开流,但没有乐趣。所以有人请找出如何回放这些数据!:-模型只是我拥有的一个对象,用于由多个对象共享的全局数据。因此,我有一个名为model的数据模型对象,它保存着我的url字符串、我听过的电台数组以及我共享的其他数据,如艺术家姓名和歌曲标题,我将它从一个对象传递到另一个对象,以获取多个位置所需的数据。可能不是最好的方法,但它可以工作。mp3文件生成,但不能播放。你试过播放那个文件吗?如果播放成功,请告诉我。感谢该文件未使用AVAudioPlayer加载。我想数据写得不对。请多指点。AudioPlayer未正确加载:错误域=NSOSStatusErrorDomain代码=1685348671操作无法完成。OSStatus错误1685348671。需要注意的一点是:许多流包含歌曲、艺术家或其他信息的元数据。如果你也记录了这些数据,当你回放时,当这些数据经过时,你会听到有规律的滴答声。如果您在播放时听到噪音,这就是原因。虽然此链接可以回答问题,但最好在此处包含答案的基本部分,并提供链接以供参考。如果链接页面更改,只有链接的答案可能无效。我说的是streming类,我想提供一个该类的zip,所以添加此链接以直接下载