Ну, это мой самый первый пост в истории - между этим сайтом, личными блогами и форумами iPhoneDevSDK я всегда мог сам разобраться. Я разрабатывал для iOS около пяти месяцев и никогда не обращался за помощью за пределами Google. Но на этот раз я застрял.
Я успешно внедрил класс AudioStream Мэтта Галагера (пришлось удалить ссылку, поскольку SO предполагает, что мой пост является спамом) в мое приложение, и я рад сообщить, что он прекрасно работает. Я использую его в одном контроллере представления, который на самом деле является дочерним по отношению к родительскому представлению в приложении TabBar. Фактически, моя реализация не сильно отличается от реализации в примере Мэтта - я изменил только некоторые элементы пользовательского интерфейса.
До этого момента я использовал viewDidDisappear
, чтобы остановить стример, когда пользователь переключается на другую вкладку. Но недавно я решил, что было бы неплохо позволить аудиопотоку воспроизводиться, пока приложение работает, независимо от того, какой вид сверху. Это было очень простое изменение, и теперь мой аудиопоток продолжает воспроизводиться независимо от того, где я нахожусь в приложении.
Вот как работает контроллер вида:
- У меня кнопка Play и кнопка Stop лежат в одном месте со скрытой кнопкой Stop.
- Когда пользователь нажимает кнопку Play, кнопка Play скрывается, открывая UIActivityIndicatorView (`[streamer isWaiting]`)
- Когда поток начинает воспроизводиться (`[streamer isPlaying]`), `UIActivityIndicatorView` скрывается, и появляется кнопка Stop
- Кроме того, пока `[streamer isPlaying]`, я отображаю прошедшее время (мм: сс) в окне навигации, которое обновляется каждую секунду
Все вышеперечисленное прекрасно работает каждый раз. Если я покину вид (либо нажав на родительский вид, либо перейдя на другую вкладку), звук продолжит воспроизводиться, и это именно то, что я хочу. Но когда я возвращаюсь к представлению, пользовательский интерфейс выглядит так, как будто я его еще не запустил (видна кнопка «Воспроизвести», подсказка навигации скрыта). Если я нажимаю кнопку воспроизведения, я слышу второй поток, воспроизводимый одновременно с первым.
Кажется, что updateProgress
остановился (так как self.navigationItem.prompt
больше не виден), и я предполагаю, что playbackStateChanged
"мертв" (не знаю, как это описать).
Я часами разбирался в классе AudioStreamer, пытаясь выяснить, как сохранить контроль над потоком, но я измотан. Я надеюсь, что кто-то сможет сказать мне, что мне не хватает.
Как я уже говорил ранее, мой контроллер представления почти идентичен примеру (см. Гиперссылку выше, поскольку SO по-прежнему предполагает, что я спамер), только с некоторыми изменениями, связанными с пользовательским интерфейсом.
Полагаю, короткий вопрос был бы таков: смог ли кто-нибудь реализовать класс AudioSTreamer, открыть его представление, затем вернуться и иметь возможность просматривать истекшее время или остановить поток?
РЕДАКТИРОВАТЬ: ниже мой контроллер представления, реализующий AudioStreamer
.h
#import <UIKit/UIKit.h>
#import <QuartzCore/CoreAnimation.h>
#import <MediaPlayer/MediaPlayer.h>
#import <CFNetwork/CFNetwork.h>
@class AudioStreamer;
@interface RadioViewController : UIViewController
{
IBOutlet UIButton *playButton;
IBOutlet UIButton *stopButton;
IBOutlet UIActivityIndicatorView *waitIndicator;
AudioStreamer *streamer;
NSTimer *progressUpdateTimer;
BOOL shouldAutoStop;
}
- (IBAction)play;
- (IBAction)stop;
- (void)createStreamer;
- (void)destroyStreamer;
- (void)updateProgress:(NSTimer *)aNotification;
- (void)checkWiFi;
@end
.m
#import "AudioStreamer.h"
#import "ServerCheck.h"
#import "RadioViewController.h"
@implementation RadioViewController
- (void)viewDidLoad
{
[[self navigationItem] setTitle:@"WXK33 162.550"];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(checkWiFi) name:UIApplicationDidBecomeActiveNotification object:nil];
[super viewDidLoad];
}
- (void)viewDidAppear:(BOOL)animated
{
[self performSelector:@selector(checkWiFi)];
[super viewDidAppear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
//[self performSelector:@selector(stop)];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];
[super viewDidDisappear:animated];
}
- (void)createStreamer
{
if ([ServerCheck serverReachable:@"audiostream.wunderground.com"])
{
if (streamer)
{
return;
}
[self destroyStreamer];
NSURL *url = [NSURL URLWithString:@"http://audiostream.wunderground.com/MaffooClock/San_Angelo.mp3"];
streamer = [[AudioStreamer alloc] initWithURL:url];
progressUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateProgress:) userInfo:nil repeats:YES];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackStateChanged:) name:ASStatusChangedNotification object:streamer];
}
else
{
[[self navigationController] popViewControllerAnimated:YES];
}
}
- (IBAction)play
{
[self createStreamer];
[waitIndicator startAnimating];
[streamer start];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
}
- (IBAction)stop
{
self.navigationItem.prompt = nil;
[streamer stop];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
}
- (void)playbackStateChanged:(NSNotification *)aNotification
{
if ([streamer isWaiting])
{
[playButton setHidden:YES];
[stopButton setHidden:YES];
[waitIndicator startAnimating];
}
else if ([streamer isPlaying])
{
[playButton setHidden:YES];
[stopButton setHidden:NO];
[waitIndicator stopAnimating];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
}
else if ([streamer isIdle])
{
[self destroyStreamer];
[playButton setHidden:NO];
[stopButton setHidden:YES];
[waitIndicator stopAnimating];
}
}
- (void)updateProgress:(NSTimer *)updatedTimer
{
if (streamer.bitRate > 0.0)
{
double progress = streamer.progress;
double minutes = floor(progress/60);
double seconds = trunc(progress - (minutes * 60));
self.navigationItem.prompt = [NSString stringWithFormat:@"Elapsed: %02.0f:%02.0f",minutes,seconds];;
if (shouldAutoStop && progress > 600)
[self performSelector:@selector(stop)];
}
else
{
self.navigationItem.prompt = nil;
}
}
- (void) checkWiFi
{
if (![ServerCheck wifiAvailable])
{
LogInfo(@"No Wi-Fi");
NSString * messageTitle = @"Notice";
NSString * messageText = @"It appears that you do not have an active Wi-Fi connection. Listening to streaming audio via cellular data may incurr additional data charges. Streaming will automatically stop after 10 minutes.";
UIAlertView *errorAlert = [[UIAlertView alloc] initWithTitle:messageTitle message:messageText delegate:self cancelButtonTitle:@"Dismiss" otherButtonTitles:nil];
[errorAlert show];
[errorAlert release];
shouldAutoStop = YES;
}
else
shouldAutoStop = NO;
}
- (void)destroyStreamer
{
if (streamer)
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:ASStatusChangedNotification object:streamer];
[progressUpdateTimer invalidate];
progressUpdateTimer = nil;
[streamer stop];
[streamer release], streamer = nil;
}
}
- (void)dealloc
{
[self destroyStreamer];
if (progressUpdateTimer)
{
[progressUpdateTimer invalidate], progressUpdateTimer = nil;
}
[super dealloc];
}
@end