将音频从服务器传输到iPhone

时间:2022-02-19 14:46:25

I'm looking to stream some audio files I have on my server to an iPhone-client application I'm writing. Some of the audio files can be rather large in size, even after compression. My question is, is there a Cocoa framework that helps me with buffering the audio so it becomes available to the user while the rest is being brought down the pipes? If not, can anyone point me in the right direction to learn more about the technologies required to make such a thing happen using Objective-C/Cocoa?

我想把我的服务器上的一些音频文件传输到我正在写的一个iphone客户端应用程序。有些音频文件的大小可以相当大,即使压缩之后也是如此。我的问题是,是否有一个Cocoa框架可以帮助我缓冲音频,以便用户在其他的声音被拖下管道时可以使用它?如果没有,谁能给我指出正确的方向,让我更多地了解使用Objective-C/Cocoa来实现这种事情所需的技术?

A definitive resource on buffering and compression of audio from a server<->client infrastructure would be ideal.

从服务器<->客户端基础结构缓冲和压缩音频的最终资源是理想的。

5 个解决方案

#1


24  

Brad mentioned a post that I wrote to stream audio via HTTP. That was this one: Streaming and playing an MP3. I don't mean to be the person that links to his own blog but it does kind of address your question.

Brad提到了我写的一篇文章,是关于通过HTTP传输音频的。就是这个:流媒体和播放MP3。我并不是想成为链接到他自己博客的那个人,但它确实能解决你的问题。

In regards to how hard the problem is to solve, you'll notice I've made 4 updates to that post (way more than I've done for anything else), fixing threading errors, memory leaks and network buffering issues. There is a lot to get precisely correct.

关于解决这个问题有多困难,您将注意到我对这篇文章做了4次更新(比我在其他任何事情上做的都多),修复线程错误、内存泄漏和网络缓冲问题。有很多东西需要精确地校正。

#2


5  

MPMoviePlayerController can play audio files. If you initialize the object with a content url (this can be an Mp3 file on a server, for instance) it will stream the file and play it back.

mpmovieercontroller可以播放音频文件。如果使用内容url(例如服务器上的Mp3文件)初始化对象,它将流文件并回放。

The initialization looks like this:

初始化是这样的:

NSURL *theURL = [NSURL urlWithString:@"http://yourdomain.com/yourmediafile.mp3"];

MPMoviePlayerController* yourPlayerController = [[MPMoviePlayerController alloc] initWithContentURL:theURL];

From there you can pop up a playback view that will show a slider for scrubbing through the content, and it will fill in the slider bar as the content buffers.

从那里,您可以弹出一个回放视图,该视图将显示一个用于清理内容的滑动条,它将填充作为内容缓冲区的滑动条。

[yourPlayerController shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationLandscapeRight];
[self presentMoviePlayerViewControllerAnimated:yourPlayerController];

Or you could just make it play and create your own UI:

或者你可以让它播放并创建你自己的UI:

[yourPlayerController.moviePlayer play];

This method of playback will cut off the audio when the screen locks unless you tell the app to run in the background in the info.plist file.

这种回放方法将在屏幕锁住时切断音频,除非你告诉应用程序在info中的后台运行。plist文件。

#3


2  

Unfortunatally, you are going to have a bit of work in front of you. I had to do this for an iPhone project this last summer. Most of what you need is in Audio Queue Services in the AudioToolbox framwork.

不幸的是,你将会有一些工作要做。去年夏天,我不得不为iPhone项目做这个。您需要的大部分内容是在AudioToolbox框架工作中的音频队列服务中。

Working with audio queue services is kind of tricky, you will have to implement a bunch of callbacks to tell it how to processes your packets after they come off the network.

使用音频队列服务有点棘手,您必须实现一堆回调,告诉它如何在数据包离开网络后处理它们。

Someone, I think Matt Gallagar, had some sample code on a blog that was okay, and there is a bunch of stuff on Apple's Core Audio Mailing List.

我认为有些人,Matt Gallagar,在一个博客上有一些样本代码是可以的,而且在苹果的核心音频邮件列表上有很多东西。

I did find that I ended up needing to not relay on NSURL Connection to do the network part, because my didrecievedata delegate method was not firing often enough.

我发现我最终不需要在NSURL连接上中继来做网络部分,因为我的didrecievedata委托方法不够频繁。

Sorry I could not just drop in a few lines of code as an example here, but the class I wrote to do this came in at around 400 lines.

不好意思,我不能只写几行代码作为例子,我写的这个类大概有400行。

#4


2  

I know by now that you hopefully have solved your problem. But just incase. If you want a straight forward solution, you can always get the embeded code or any other link and make an html file out of it. Like

我现在知道你希望已经解决了你的问题。只是装进箱。如果您想要一个直接的解决方案,您总是可以获得嵌入的代码或任何其他链接,并从中创建一个html文件。就像

<html>
<body>
<script type="text/javascript">
  var embedBaseUrl = 'http://www.tv.net/';
  var embedChannelId = 13;
  var embedSize = [300,250];
  var embedAutoplay = true;
</script>
<script type="text/javascript"src="http://www.tv.net/assets/js/embed.js"></script>
</body>
</HTML>

ViewController.h

ViewController.h

@interface ViewController : UIViewController {

NSString *videoURL;

}

@property (nonatomic, strong) NSString *videoURL;

    (IBAction) tv;

And in the ViewController.m

而在ViewController.m

@synthesize videoURL;

    (IBAction) tv {

    self.videoURL = @"http://dl.dropbox.com/x/xxxxxxxx/HTML/tv.html";

    VideoViewController *videoViewController = [[VideoViewController alloc] initWithNibName:nil bundle:nil];

    videoViewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal; videoViewController.videoURL = self.videoURL;

    [self presentViewController:videoViewController animated:YES completion:nil]; }

And then in VideoViewController.h

然后在VideoViewController.h

IBOutlet UIWebView *videoView;

NSString *videoURL; NSString *videoHTML;

}

@property(nonatomic, retain) IBOutlet UIWebView *videoView; @property(nonatomic, retain) NSString *videoURL; @property(nonatomic, retain) NSString *videoHTML;

    (void) embedTV;

VideoViewController.m

@synthesize videoView, videoURL, videoHTML;

    (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { // Custom initialization } return self; }

    (void)embedTV {

    videoHTML = [NSString stringWithFormat:@"\ \ \ \ iframe {position:absolute; top:50%%; margin-top:-130px;}\ body {background-color:#000; margin:0;}\ \ \ \ \ \ ", videoURL];

    [videoView loadHTMLString:videoHTML baseURL:nil]; }
        (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view from its nib.

    videoView.backgroundColor = [UIColor blackColor]; videoView.opaque = NO;

    [self embedTV]; }

Now in my example I referred to video stream, but you get the point, you can stream or play what you want. Simply just use UIWebView.

在我的例子中,我提到了视频流,但是你得到了要点,你可以视频流或播放你想要的。只是使用UIWebView。

#5


1  

You can use the AVPlayer class from the AVFoundation framework to stream audio from local files or from a remote server. The AVPlayer class will notify you about readiness to play or about the need to buffer more data.

您可以使用来自AVFoundation框架的AVPlayer类来从本地文件或远程服务器传输音频。AVPlayer类将通知您是否准备就绪,或者是否需要缓冲更多的数据。

However if you want more control you should definitely use Audio Queue services. Using Audio Queue services is a little bit harder but once you get the hang of it you'll be able to fine-tune the audio playback process the way you want it.

然而,如果您想要更多的控制,您一定要使用音频队列服务。使用音频队列服务有点难,但是一旦你掌握了它,你就可以按照你想要的方式对音频播放过程进行微调。

#1


24  

Brad mentioned a post that I wrote to stream audio via HTTP. That was this one: Streaming and playing an MP3. I don't mean to be the person that links to his own blog but it does kind of address your question.

Brad提到了我写的一篇文章,是关于通过HTTP传输音频的。就是这个:流媒体和播放MP3。我并不是想成为链接到他自己博客的那个人,但它确实能解决你的问题。

In regards to how hard the problem is to solve, you'll notice I've made 4 updates to that post (way more than I've done for anything else), fixing threading errors, memory leaks and network buffering issues. There is a lot to get precisely correct.

关于解决这个问题有多困难,您将注意到我对这篇文章做了4次更新(比我在其他任何事情上做的都多),修复线程错误、内存泄漏和网络缓冲问题。有很多东西需要精确地校正。

#2


5  

MPMoviePlayerController can play audio files. If you initialize the object with a content url (this can be an Mp3 file on a server, for instance) it will stream the file and play it back.

mpmovieercontroller可以播放音频文件。如果使用内容url(例如服务器上的Mp3文件)初始化对象,它将流文件并回放。

The initialization looks like this:

初始化是这样的:

NSURL *theURL = [NSURL urlWithString:@"http://yourdomain.com/yourmediafile.mp3"];

MPMoviePlayerController* yourPlayerController = [[MPMoviePlayerController alloc] initWithContentURL:theURL];

From there you can pop up a playback view that will show a slider for scrubbing through the content, and it will fill in the slider bar as the content buffers.

从那里,您可以弹出一个回放视图,该视图将显示一个用于清理内容的滑动条,它将填充作为内容缓冲区的滑动条。

[yourPlayerController shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationLandscapeRight];
[self presentMoviePlayerViewControllerAnimated:yourPlayerController];

Or you could just make it play and create your own UI:

或者你可以让它播放并创建你自己的UI:

[yourPlayerController.moviePlayer play];

This method of playback will cut off the audio when the screen locks unless you tell the app to run in the background in the info.plist file.

这种回放方法将在屏幕锁住时切断音频,除非你告诉应用程序在info中的后台运行。plist文件。

#3


2  

Unfortunatally, you are going to have a bit of work in front of you. I had to do this for an iPhone project this last summer. Most of what you need is in Audio Queue Services in the AudioToolbox framwork.

不幸的是,你将会有一些工作要做。去年夏天,我不得不为iPhone项目做这个。您需要的大部分内容是在AudioToolbox框架工作中的音频队列服务中。

Working with audio queue services is kind of tricky, you will have to implement a bunch of callbacks to tell it how to processes your packets after they come off the network.

使用音频队列服务有点棘手,您必须实现一堆回调,告诉它如何在数据包离开网络后处理它们。

Someone, I think Matt Gallagar, had some sample code on a blog that was okay, and there is a bunch of stuff on Apple's Core Audio Mailing List.

我认为有些人,Matt Gallagar,在一个博客上有一些样本代码是可以的,而且在苹果的核心音频邮件列表上有很多东西。

I did find that I ended up needing to not relay on NSURL Connection to do the network part, because my didrecievedata delegate method was not firing often enough.

我发现我最终不需要在NSURL连接上中继来做网络部分,因为我的didrecievedata委托方法不够频繁。

Sorry I could not just drop in a few lines of code as an example here, but the class I wrote to do this came in at around 400 lines.

不好意思,我不能只写几行代码作为例子,我写的这个类大概有400行。

#4


2  

I know by now that you hopefully have solved your problem. But just incase. If you want a straight forward solution, you can always get the embeded code or any other link and make an html file out of it. Like

我现在知道你希望已经解决了你的问题。只是装进箱。如果您想要一个直接的解决方案,您总是可以获得嵌入的代码或任何其他链接,并从中创建一个html文件。就像

<html>
<body>
<script type="text/javascript">
  var embedBaseUrl = 'http://www.tv.net/';
  var embedChannelId = 13;
  var embedSize = [300,250];
  var embedAutoplay = true;
</script>
<script type="text/javascript"src="http://www.tv.net/assets/js/embed.js"></script>
</body>
</HTML>

ViewController.h

ViewController.h

@interface ViewController : UIViewController {

NSString *videoURL;

}

@property (nonatomic, strong) NSString *videoURL;

    (IBAction) tv;

And in the ViewController.m

而在ViewController.m

@synthesize videoURL;

    (IBAction) tv {

    self.videoURL = @"http://dl.dropbox.com/x/xxxxxxxx/HTML/tv.html";

    VideoViewController *videoViewController = [[VideoViewController alloc] initWithNibName:nil bundle:nil];

    videoViewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal; videoViewController.videoURL = self.videoURL;

    [self presentViewController:videoViewController animated:YES completion:nil]; }

And then in VideoViewController.h

然后在VideoViewController.h

IBOutlet UIWebView *videoView;

NSString *videoURL; NSString *videoHTML;

}

@property(nonatomic, retain) IBOutlet UIWebView *videoView; @property(nonatomic, retain) NSString *videoURL; @property(nonatomic, retain) NSString *videoHTML;

    (void) embedTV;

VideoViewController.m

@synthesize videoView, videoURL, videoHTML;

    (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { // Custom initialization } return self; }

    (void)embedTV {

    videoHTML = [NSString stringWithFormat:@"\ \ \ \ iframe {position:absolute; top:50%%; margin-top:-130px;}\ body {background-color:#000; margin:0;}\ \ \ \ \ \ ", videoURL];

    [videoView loadHTMLString:videoHTML baseURL:nil]; }
        (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view from its nib.

    videoView.backgroundColor = [UIColor blackColor]; videoView.opaque = NO;

    [self embedTV]; }

Now in my example I referred to video stream, but you get the point, you can stream or play what you want. Simply just use UIWebView.

在我的例子中,我提到了视频流,但是你得到了要点,你可以视频流或播放你想要的。只是使用UIWebView。

#5


1  

You can use the AVPlayer class from the AVFoundation framework to stream audio from local files or from a remote server. The AVPlayer class will notify you about readiness to play or about the need to buffer more data.

您可以使用来自AVFoundation框架的AVPlayer类来从本地文件或远程服务器传输音频。AVPlayer类将通知您是否准备就绪,或者是否需要缓冲更多的数据。

However if you want more control you should definitely use Audio Queue services. Using Audio Queue services is a little bit harder but once you get the hang of it you'll be able to fine-tune the audio playback process the way you want it.

然而,如果您想要更多的控制,您一定要使用音频队列服务。使用音频队列服务有点难,但是一旦你掌握了它,你就可以按照你想要的方式对音频播放过程进行微调。