StreamingKit/ExampleApp/ExampleApp/AudioPlayerView.m

379 lines
13 KiB
Objective-C

/**********************************************************************************
AudioPlayer.m
Created by Thong Nguyen on 14/05/2012.
https://github.com/tumtumtum/audjustable
Copyright (c) 2012 Thong Nguyen (tumtumtum@gmail.com). All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. All advertising materials mentioning features or use of this software
must display the following acknowledgement:
This product includes software developed by Thong Nguyen (tumtumtum@gmail.com)
4. Neither the name of Thong Nguyen nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY Thong Nguyen ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THONG NGUYEN BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**********************************************************************************/
#import "AudioPlayerView.h"
#import "SampleQueueId.h"
///
/// This sample media player will play a local or an HTTP stream in repeat (gapless)
///
@interface AudioPlayerView()
-(void) setupTimer;
-(void) updateControls;
@end
@implementation AudioPlayerView
@synthesize audioPlayer, delegate;
- (id)initWithFrame:(CGRect)frame andAudioPlayer:(STKAudioPlayer*)audioPlayerIn
{
self = [super initWithFrame:frame];
if (self)
{
self.audioPlayer = audioPlayerIn;
CGSize size = CGSizeMake(220, 50);
playFromHTTPButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
playFromHTTPButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10, size.width, size.height);
[playFromHTTPButton addTarget:self action:@selector(playFromHTTPButtonTouched) forControlEvents:UIControlEventTouchUpInside];
[playFromHTTPButton setTitle:@"Play from HTTP" forState:UIControlStateNormal];
playFromIcecastButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
playFromIcecastButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10 + 35, size.width, size.height);
[playFromIcecastButton addTarget:self action:@selector(playFromIcecasButtonTouched) forControlEvents:UIControlEventTouchUpInside];
[playFromIcecastButton setTitle:@"Play from Icecast" forState:UIControlStateNormal];
playFromLocalFileButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
playFromLocalFileButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10 + 70, size.width, size.height);
[playFromLocalFileButton addTarget:self action:@selector(playFromLocalFileButtonTouched) forControlEvents:UIControlEventTouchUpInside];
[playFromLocalFileButton setTitle:@"Play from Local File" forState:UIControlStateNormal];
queueShortFileButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
queueShortFileButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10 + 105, size.width, size.height);
[queueShortFileButton addTarget:self action:@selector(queueShortFileButtonTouched) forControlEvents:UIControlEventTouchUpInside];
[queueShortFileButton setTitle:@"Queue short file" forState:UIControlStateNormal];
queuePcmWaveFileFromHTTPButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
queuePcmWaveFileFromHTTPButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10 + 140, size.width, size.height);
[queuePcmWaveFileFromHTTPButton addTarget:self action:@selector(queuePcmWaveFileButtonTouched) forControlEvents:UIControlEventTouchUpInside];
[queuePcmWaveFileFromHTTPButton setTitle:@"Queue PCM/WAVE from HTTP" forState:UIControlStateNormal];
size = CGSizeMake(90, 40);
playButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
playButton.frame = CGRectMake(30, 400, size.width, size.height);
[playButton addTarget:self action:@selector(playButtonPressed) forControlEvents:UIControlEventTouchUpInside];
stopButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
stopButton.frame = CGRectMake((320 - size.width) - 30, 400, size.width, size.height);
[stopButton addTarget:self action:@selector(stopButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[stopButton setTitle:@"Stop" forState:UIControlStateNormal];
muteButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
muteButton.frame = CGRectMake((320 - size.width) - 30, 430, size.width, size.height);
[muteButton addTarget:self action:@selector(muteButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[muteButton setTitle:@"Mute" forState:UIControlStateNormal];
slider = [[UISlider alloc] initWithFrame:CGRectMake(20, 320, queuePcmWaveFileFromHTTPButton.frame.origin.y + queuePcmWaveFileFromHTTPButton.frame.size.height + 20, 20)];
slider.continuous = YES;
[slider addTarget:self action:@selector(sliderChanged) forControlEvents:UIControlEventValueChanged];
size = CGSizeMake(80, 50);
repeatSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(30, frame.size.height * 0.15 + 180, size.width, size.height)];
enableEqSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(320 - size.width - 30, frame.size.height * 0.15 + 180, size.width, size.height)];
enableEqSwitch.on = audioPlayer.equalizerEnabled;
[enableEqSwitch addTarget:self action:@selector(onEnableEqSwitch) forControlEvents:UIControlEventAllTouchEvents];
label = [[UILabel alloc] initWithFrame:CGRectMake(0, slider.frame.origin.y + slider.frame.size.height + 40, frame.size.width, 25)];
label.textAlignment = NSTextAlignmentCenter;
statusLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, slider.frame.origin.y + slider.frame.size.height + label.frame.size.height + 50, frame.size.width, 50)];
statusLabel.textAlignment = NSTextAlignmentCenter;
meter = [[UIView alloc] initWithFrame:CGRectMake(0, 450, 0, 20)];
meter.backgroundColor = [UIColor greenColor];
[self addSubview:slider];
[self addSubview:playButton];
[self addSubview:playFromHTTPButton];
[self addSubview:playFromIcecastButton];
[self addSubview:playFromLocalFileButton];
[self addSubview:queueShortFileButton];
[self addSubview:queuePcmWaveFileFromHTTPButton];
[self addSubview:repeatSwitch];
[self addSubview:label];
[self addSubview:statusLabel];
[self addSubview:stopButton];
[self addSubview:meter];
[self addSubview:muteButton];
[self addSubview:enableEqSwitch];
[self setupTimer];
[self updateControls];
}
return self;
}
-(void) onEnableEqSwitch
{
audioPlayer.equalizerEnabled = self->enableEqSwitch.on;
}
-(void) sliderChanged
{
if (!audioPlayer)
{
return;
}
NSLog(@"Slider Changed: %f", slider.value);
[audioPlayer seekToTime:slider.value];
}
-(void) setupTimer
{
timer = [NSTimer timerWithTimeInterval:0.001 target:self selector:@selector(tick) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}
-(void) tick
{
if (!audioPlayer)
{
slider.value = 0;
label.text = @"";
statusLabel.text = @"";
return;
}
if (audioPlayer.currentlyPlayingQueueItemId == nil)
{
slider.value = 0;
slider.minimumValue = 0;
slider.maximumValue = 0;
label.text = @"";
return;
}
if (audioPlayer.duration != 0)
{
slider.minimumValue = 0;
slider.maximumValue = audioPlayer.duration;
slider.value = audioPlayer.progress;
label.text = [NSString stringWithFormat:@"%@ - %@", [self formatTimeFromSeconds:audioPlayer.progress], [self formatTimeFromSeconds:audioPlayer.duration]];
}
else
{
slider.value = 0;
slider.minimumValue = 0;
slider.maximumValue = 0;
label.text = [NSString stringWithFormat:@"Live stream %@", [self formatTimeFromSeconds:audioPlayer.progress]];
}
statusLabel.text = audioPlayer.state == STKAudioPlayerStateBuffering ? @"buffering" : @"";
CGFloat newWidth = 320 * (([audioPlayer averagePowerInDecibelsForChannel:1] + 60) / 60);
meter.frame = CGRectMake(0, 460, newWidth, 20);
}
-(void) playFromHTTPButtonTouched
{
[self.delegate audioPlayerViewPlayFromHTTPSelected:self];
}
-(void) playFromIcecasButtonTouched
{
[self.delegate audioPlayerViewPlayFromIcecastSelected:self];
}
-(void) playFromLocalFileButtonTouched
{
[self.delegate audioPlayerViewPlayFromLocalFileSelected:self];
}
-(void) queueShortFileButtonTouched
{
[self.delegate audioPlayerViewQueueShortFileSelected:self];
}
-(void) queuePcmWaveFileButtonTouched
{
[self.delegate audioPlayerViewQueuePcmWaveFileSelected:self];
}
-(void) muteButtonPressed
{
audioPlayer.muted = !audioPlayer.muted;
if (audioPlayer.muted)
{
[muteButton setTitle:@"Unmute" forState:UIControlStateNormal];
}
else
{
[muteButton setTitle:@"Mute" forState:UIControlStateNormal];
}
}
-(void) stopButtonPressed
{
[audioPlayer stop];
}
-(void) playButtonPressed
{
if (!audioPlayer)
{
return;
}
if (audioPlayer.state == STKAudioPlayerStatePaused)
{
[audioPlayer resume];
}
else
{
[audioPlayer pause];
}
}
-(NSString*) formatTimeFromSeconds:(int)totalSeconds
{
int seconds = totalSeconds % 60;
int minutes = (totalSeconds / 60) % 60;
int hours = totalSeconds / 3600;
return [NSString stringWithFormat:@"%02d:%02d:%02d", hours, minutes, seconds];
}
-(void) updateControls
{
if (audioPlayer == nil)
{
[playButton setTitle:@"" forState:UIControlStateNormal];
}
else if (audioPlayer.state == STKAudioPlayerStatePaused)
{
[playButton setTitle:@"Resume" forState:UIControlStateNormal];
}
else if (audioPlayer.state & STKAudioPlayerStatePlaying)
{
[playButton setTitle:@"Pause" forState:UIControlStateNormal];
}
else
{
[playButton setTitle:@"" forState:UIControlStateNormal];
}
[self tick];
}
-(void) setAudioPlayer:(STKAudioPlayer*)value
{
if (audioPlayer)
{
audioPlayer.delegate = nil;
}
audioPlayer = value;
audioPlayer.delegate = self;
[self updateControls];
}
-(STKAudioPlayer*) audioPlayer
{
return audioPlayer;
}
-(void) audioPlayer:(STKAudioPlayer*)audioPlayer stateChanged:(STKAudioPlayerState)state previousState:(STKAudioPlayerState)previousState
{
[self updateControls];
}
-(void) audioPlayer:(STKAudioPlayer*)audioPlayer unexpectedError:(STKAudioPlayerErrorCode)errorCode
{
[self updateControls];
}
-(void) audioPlayer:(STKAudioPlayer*)audioPlayer didStartPlayingQueueItemId:(NSObject*)queueItemId
{
SampleQueueId* queueId = (SampleQueueId*)queueItemId;
NSLog(@"Started: %@", [queueId.url description]);
[self updateControls];
}
-(void) audioPlayer:(STKAudioPlayer*)audioPlayer didFinishBufferingSourceWithQueueItemId:(NSObject*)queueItemId
{
[self updateControls];
// This queues on the currently playing track to be buffered and played immediately after (gapless)
if (repeatSwitch.on)
{
SampleQueueId* queueId = (SampleQueueId*)queueItemId;
NSLog(@"Requeuing: %@", [queueId.url description]);
[self->audioPlayer queueDataSource:[STKAudioPlayer dataSourceFromURL:queueId.url] withQueueItemId:[[SampleQueueId alloc] initWithUrl:queueId.url andCount:queueId.count + 1]];
}
}
-(void) audioPlayer:(STKAudioPlayer*)audioPlayer didFinishPlayingQueueItemId:(NSObject*)queueItemId withReason:(STKAudioPlayerStopReason)stopReason andProgress:(double)progress andDuration:(double)duration
{
[self updateControls];
SampleQueueId* queueId = (SampleQueueId*)queueItemId;
NSLog(@"Finished: %@", [queueId.url description]);
}
-(void) audioPlayer:(STKAudioPlayer *)audioPlayer logInfo:(NSString *)line
{
NSLog(@"%@", line);
}
@end