source: trunk/SapphireFrappliance/Players/SapphireAudioPlayer.m @ 947

Revision 947, 7.4 KB checked in by gbooker, 5 years ago (diff)

Audio player is now responsive on later ATV versions.

Line 
1/*
2 * SapphireAudioPlayer.m
3 * Sapphire
4 *
5 * Created by Graham Booker on Jul. 28, 2007.
6 * Copyright 2007 Sapphire Development Team and/or www.nanopi.net
7 * All rights reserved.
8 *
9 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
10 * General Public License as published by the Free Software Foundation; either version 3 of the License,
11 * or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
14 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
15 * Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along with this program; if not,
18 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19 */
20
21#import <SapphireCompatClasses/SapphireFrontRowCompat.h>
22#import "SapphireAudioPlayer.h"
23#import "SapphireAudioMedia.h"
24#import "SapphireFileMetaData.h"
25#import "SapphireVideoPlayerController.h"
26#import <QTKit/QTKit.h>
27
28#define SKIP_INTERVAL 0.5
29#define SKIP_ACCELL 0.5 * SKIP_INTERVAL
30
31@interface BRMusicPlayer (compat)
32-(BOOL)setMedia:(id)media inTrackList:(id)trackList error:(NSError **)error;
33-(BOOL)setMediaAtIndex:(long)index inTrackList:(id)trackList error:(NSError **)error;
34@end
35
36//Stolen from ATVFiles
37typedef enum {
38        BRMusicPlayerStateStopped = 0,
39        BRMusicPlayerStatePaused = 1,
40        BRMusicPlayerStatePlaying = 3,
41        BRMusicPlayerStateSeekingForward = 4,
42        BRMusicPlayerStateSeekingBack = 7
43} BRMusicPlayerState;
44
45@interface SapphireAudioPlayer (private)
46- (void)setState:(int)newState;
47- (void)stopUITimer;
48- (void)setSkipTimer;
49- (void)doSkip:(NSTimer *)timer;
50- (void)stopSkip;
51- (void)updateUI:(NSTimer *)Timer;
52- (void)setPlayerState:(BRMusicPlayerState)newState;
53@end
54
55@implementation SapphireAudioPlayer
56
57- (id) init {
58        self = [super init];
59        if (self == nil)
60                return nil;
61
62        state = 0;
63
64        return self;
65}
66
67- (void) dealloc
68{
69        [movie release];
70        [self stopUITimer];
71        [self stopSkip];
72        [myMedia release];
73        [myTrackList release];
74        [super dealloc];
75}
76
77- (int)playerState
78{
79        return state;
80}
81
82- (void)setMedia:(SapphireAudioMedia *)media inTracklist:(NSArray *)tracklist error:(NSError * *)error
83{
84        SapphireFrontRowCompatATVVersion version = [SapphireFrontRowCompat atvVersion];
85        if(version >= SapphireFrontRowCompatATVVersion2Dot3)
86                [super setMediaAtIndex:[tracklist indexOfObject:media] inTrackList:tracklist error:error];
87        else if (version >= SapphireFrontRowCompatATVVersion2Dot2)
88                [super setMedia:media inTrackList:tracklist error:error];
89        else
90                [super setMedia:media inTracklist:tracklist error:error];
91       
92        [myMedia release];
93        [myTrackList release];
94        myMedia = [media retain];
95        myTrackList = [tracklist retain];
96       
97        if(error != NULL && *error == nil)
98        {
99                soundState = enablePassthrough([media fileMetaData]);
100                movie = [[QTMovie alloc] initWithURL:[NSURL URLWithString:[media mediaURL]] error:error];
101                [media setMovie:movie];
102                [self setElapsedPlaybackTime:[media bookmarkTimeInSeconds]];
103        }
104        [[NSNotificationCenter defaultCenter] postNotificationName:kBRMediaPlayerCurrentAssetChanged object:media];
105        [[NSNotificationCenter defaultCenter] postNotificationName:@"BRMPCurrentAssetChanged" object:media];
106}
107
108- (SapphireAudioMedia *)media
109{
110        return myMedia;
111}
112
113- (NSArray *)tracklist
114{
115        return myTrackList;
116}
117
118- (float)elapsedPlaybackTime
119{
120        QTTime current = [movie currentTime];
121        double ret = 0.0;
122        QTGetTimeInterval(current, &ret);
123        return (float)ret;
124}
125
126- (double)elapsedTime
127{
128        return [self elapsedPlaybackTime];
129}
130
131- (void)setElapsedPlaybackTime:(float)time
132{
133        QTTime newTime = QTMakeTimeWithTimeInterval((double)time);
134        [movie setCurrentTime:newTime];
135        [self updateUI:nil];
136}
137
138- (double)trackDuration
139{
140        QTTime duration = [movie duration];
141        double ret = 0.0;
142        QTGetTimeInterval(duration, &ret);
143        return (float)ret;
144}
145
146- (NSString *)currentChapterTitle
147{
148        return [movie attributeForKey:QTMovieDisplayNameAttribute];
149}
150
151- (BOOL)initiatePlayback:(NSError * *)error
152{
153        [movie stop];
154        [movie gotoBeginning];
155        return YES;
156}
157
158-(void)setState:(int)newState error:(NSError **)error
159{
160        [self setPlayerState:newState];
161}
162
163- (void)setState:(int)newState
164{
165        [self setPlayerState:newState];
166}
167
168- (void)setPlayerState:(BRMusicPlayerState)newState
169{
170        state = newState;
171        switch (state) {
172                case BRMusicPlayerStatePlaying:
173                {
174                        id media = [self media];
175                        [[NSNotificationCenter defaultCenter] postNotificationName:kBRMediaPlayerCurrentAssetChanged object:media];
176                        [[NSNotificationCenter defaultCenter] postNotificationName:@"BRMPCurrentAssetChanged" object:media];
177                        [self stopSkip];
178                        updateTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updateUI:) userInfo:nil repeats:YES];
179                        [movie play];
180                        break;
181                }
182                case BRMusicPlayerStatePaused:
183                        [self stopSkip];
184                        [self stopUITimer];
185                        [movie stop];
186                        break;
187                case BRMusicPlayerStateStopped:
188                        [self stopSkip];
189                        [self stopUITimer];
190                        [movie stop];
191                        SapphireFileMetaData *file = [(SapphireAudioMedia *)[self media] fileMetaData];
192                        float elapsed = [self elapsedPlaybackTime];
193                        float duration = [self trackDuration];
194                        if(elapsed >= duration)
195                                [file setWatchedValue:YES];
196                        else
197                                [file setResumeTimeValue:elapsed];
198                        teardownPassthrough(soundState);
199                        break;
200                case BRMusicPlayerStateSeekingBack:
201                        [self setSkipTimer];
202                        skipSpeed = -1;
203                        break;
204                case BRMusicPlayerStateSeekingForward:
205                        [self setSkipTimer];
206                        skipSpeed = 1;
207                        break;
208                default:
209                        NSLog(@"I was told to go into state %d", newState);
210                        break;
211        }
212        [[NSNotificationCenter defaultCenter] postNotificationName:@"BRMPStateChanged" object:self];
213        [[NSNotificationCenter defaultCenter] postNotificationName:kBRMediaPlayerStateChanged object:self];
214}
215
216- (void)play
217{
218        [self setPlayerState:BRMusicPlayerStatePlaying];
219}
220
221- (void)pause
222{
223        [self setPlayerState:BRMusicPlayerStatePaused];
224}
225
226- (void)stop
227{
228        [self setPlayerState:BRMusicPlayerStateStopped];
229}
230
231- (void)stopUITimer
232{
233        [updateTimer invalidate];
234        updateTimer = nil;
235}
236
237- (void)pressAndHoldLeftArrow
238{
239        [self setPlayerState:BRMusicPlayerStateSeekingBack];
240}
241
242- (void)pressAndHoldRightArrow
243{
244        [self setPlayerState:BRMusicPlayerStateSeekingForward];
245}
246
247- (void)setSkipTimer
248{
249        [self stopSkip];
250        skipTimer = [NSTimer scheduledTimerWithTimeInterval:SKIP_INTERVAL target:self selector:@selector(doSkip:) userInfo:nil repeats:YES];
251        [self doSkip:nil];
252}
253
254- (void)doSkip:(NSTimer *)timer
255{
256        float time = [self elapsedPlaybackTime];
257        if(skipSpeed < 0)
258        {
259                time += skipSpeed * SKIP_INTERVAL * 3;
260                skipSpeed = MAX(skipSpeed - SKIP_ACCELL, -16);
261        }
262        else
263        {
264                time += skipSpeed * SKIP_INTERVAL * 2;
265                skipSpeed = MIN(skipSpeed + SKIP_ACCELL, 16);
266        }
267        double duration = [self trackDuration];
268        if(time < 0)
269        {
270                time = 0;
271                [self stopSkip];
272        }
273        else if(time > duration)
274        {
275                time = duration;
276        }
277        [self setElapsedPlaybackTime:time];
278        [self updateUI:timer];
279}
280
281- (void)stopSkip
282{
283        skipSpeed = 0;
284        [skipTimer invalidate];
285        skipTimer = nil;
286}
287
288- (void)resume
289{
290        [self play];
291}
292
293- (void)leftArrowClick
294{
295        [movie gotoBeginning];
296        [self updateUI:nil];
297}
298
299- (void)rightArrowClick
300{
301        [movie gotoEnd];
302        [self updateUI:nil];
303}
304
305- (void)updateUI:(NSTimer *)Timer
306{
307        if([self elapsedPlaybackTime] >= [self trackDuration])
308                [self stop];
309        [[NSNotificationCenter defaultCenter] postNotificationName:@"BRMPPlaybackProgressChanged" object:self];
310        [[NSNotificationCenter defaultCenter] postNotificationName:kBRMediaPlayerPlaybackProgressChanged object:self];
311}
312
313@end
Note: See TracBrowser for help on using the repository browser.