source: trunk/SapphireFrappliance/Players/SapphireVideoPlayerController.m @ 939

Revision 939, 8.1 KB checked in by gbooker, 4 years ago (diff)

A lot of Take 3 compatibility. Layouts still need a lot of work though.
Refs #323

Line 
1/*
2 * SapphireVideoPlayerController.m
3 * Sapphire
4 *
5 * Created by pnmerrill on Apr. 26, 2008.
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 <AudioUnit/AudioUnit.h>
22#import <SapphireCompatClasses/SapphireFrontRowCompat.h>
23
24#import "SapphireVideoPlayerController.h"
25#import "SapphireFileMetaData.h"
26#import "SapphireSettings.h"
27#import "SapphireMetaDataSupport.h"
28
29#define PASSTHROUGH_KEY         (CFStringRef)@"attemptPassthrough"
30#define A52_DOMIAN                      (CFStringRef)@"com.cod3r.a52codec"
31
32#define DTS_PASSTHROUGH_KEY CFSTR("attemptDTSPassthrough")
33#define PERIAN_DOMAIN CFSTR("org.perian.Perian")
34
35#define SOUND_STATE_SOUND_ENABLED                                       1
36#define SOUND_STATE_AC3_PASSTHROUGH_WAS_ENABLED         2
37#define SOUND_STATE_PLAYER_TORNDOWN                                     4
38#define SOUND_STATE_DTS_PASSTHROUGH_WAS_ENABLED         8
39
40@interface BRVideoPlayerController (compat)
41- (id)initWithPlayer:(SapphireVideoPlayer *)player;
42@end
43
44
45@implementation SapphireVideoPlayerController
46
47- (id)initWithScene:(BRRenderScene *)scene player:(SapphireVideoPlayer *)player;
48{
49        if([[BRVideoPlayerController class] instancesRespondToSelector:@selector(initWithScene:)])
50                self = [super initWithScene:scene];
51        else if([[BRVideoPlayerController class] instancesRespondToSelector:@selector(initWithPlayer:)])
52                self = [super initWithPlayer:player];
53        else
54                self = [super init];
55       
56        [self setVideoPlayer:player];
57        return self;
58}
59
60- (void) dealloc
61{
62        [currentPlayFile release];
63        [super dealloc];
64}
65
66static BOOL findCorrectDescriptionForStream(AudioStreamID streamID, int sampleRate)
67{
68        OSStatus err;
69        UInt32 propertySize = 0;
70        err = AudioStreamGetPropertyInfo(streamID, 0, kAudioStreamPropertyPhysicalFormats, &propertySize, NULL);
71       
72        if(err != noErr || propertySize == 0)
73                return NO;
74       
75        AudioStreamBasicDescription *descs = malloc(propertySize);
76        if(descs == NULL)
77                return NO;
78       
79        int formatCount = propertySize / sizeof(AudioStreamBasicDescription);
80        err = AudioStreamGetProperty(streamID, 0, kAudioStreamPropertyPhysicalFormats, &propertySize, descs);
81       
82        if(err != noErr)
83        {
84                free(descs);
85                return NO;
86        }
87       
88        int i;
89        BOOL ret = NO;
90        for(i=0; i<formatCount; i++)
91        {
92                if (descs[i].mBitsPerChannel == 16 && descs[i].mFormatID == kAudioFormatLinearPCM)
93                {
94                        if(descs[i].mSampleRate == sampleRate)
95                        {
96                                err = AudioStreamSetProperty(streamID, NULL, 0, kAudioStreamPropertyPhysicalFormat, sizeof(AudioStreamBasicDescription), descs + i);
97                                if(err != noErr)
98                                        continue;
99                                ret = YES;
100                                break;
101                        }
102                }
103        }
104        free(descs);
105        return ret;
106}
107
108static BOOL setupDevice(AudioDeviceID devID, int sampleRate)
109{
110        OSStatus err;
111        UInt32 propertySize = 0;
112        err = AudioDeviceGetPropertyInfo(devID, 0, FALSE, kAudioDevicePropertyStreams, &propertySize, NULL);
113       
114        if(err != noErr || propertySize == 0)
115                return NO;
116       
117        AudioStreamID *streams = malloc(propertySize);
118        if(streams == NULL)
119                return NO;
120       
121        int streamCount = propertySize / sizeof(AudioStreamID);
122        err = AudioDeviceGetProperty(devID, 0, FALSE, kAudioDevicePropertyStreams, &propertySize, streams);
123        if(err != noErr)
124        {
125                free(streams);
126                return NO;
127        }
128       
129        int i;
130        BOOL ret = NO;
131        for(i=0; i<streamCount; i++)
132        {
133                if(findCorrectDescriptionForStream(streams[i], sampleRate))
134                {
135                        ret = YES;
136                        break;
137                }
138        }
139        free(streams);
140        return ret;
141}
142
143static BOOL setupAudioOutput(int sampleRate)
144{
145        OSErr err;
146        UInt32 propertySize = 0;
147       
148        err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &propertySize, NULL);
149        if(err != noErr || propertySize == 0)
150                return NO;
151       
152        AudioDeviceID *devs = malloc(propertySize);
153        if(devs == NULL)
154                return NO;
155       
156        err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &propertySize, devs);
157        if(err != noErr)
158        {
159                free(devs);
160                return NO;
161        }
162       
163        int i, devCount = propertySize/sizeof(AudioDeviceID);
164        BOOL ret = NO;
165        for(i=0; i<devCount; i++)
166        {
167                if(setupDevice(devs[i], sampleRate))
168                {
169                        err = AudioHardwareSetProperty(kAudioHardwarePropertyDefaultOutputDevice, sizeof(AudioDeviceID), devs + i);
170                        if(err != noErr)
171                                continue;
172                        ret = YES;
173                        break;
174                }
175        }
176        free(devs);
177        return ret;
178}
179
180int enablePassthrough(SapphireFileMetaData *currentPlayFile)
181{
182        int soundState;
183        SapphireSettings *settings = [SapphireSettings sharedSettings];
184        BOOL useAC3Passthrough = NO;
185        BOOL useDTSPassthrough = NO;
186
187        if([settings useAC3Passthrough])
188        {
189                Float64 sampleRate = [currentPlayFile sampleRateValue];
190                UInt32 type = [currentPlayFile audioFormatIDValue];
191               
192                if((type == 'ac-3' || type == 0x6D732000) && setupAudioOutput((int)sampleRate))
193                        useAC3Passthrough = YES;
194                else if((type == 'DTS ') && setupAudioOutput((int)sampleRate))
195                        useDTSPassthrough = YES;
196        }
197       
198        Boolean temp;
199        BOOL AC3PassthroughEnabled = CFPreferencesGetAppBooleanValue(PASSTHROUGH_KEY, A52_DOMIAN, &temp);
200        BOOL DTSPassthroughEnabled = CFPreferencesGetAppBooleanValue(DTS_PASSTHROUGH_KEY, PERIAN_DOMAIN, &temp);
201        BOOL soundsWereEnabled = NO;
202        if(useAC3Passthrough || useDTSPassthrough)
203        {
204                RUIPreferences *prefs = [SapphireFrontRowCompat sharedFrontRowPreferences];
205                soundsWereEnabled = [prefs boolForKey:@"PlayFrontRowSounds"];
206                if(soundsWereEnabled)
207                        [prefs setBool:NO forKey:@"PlayFrontRowSounds"];
208        }
209        if(useAC3Passthrough)
210                CFPreferencesSetAppValue(PASSTHROUGH_KEY, (CFNumberRef)[NSNumber numberWithInt:1], A52_DOMIAN);
211        else
212                CFPreferencesSetAppValue(PASSTHROUGH_KEY, (CFNumberRef)[NSNumber numberWithInt:0], A52_DOMIAN);
213        if(useDTSPassthrough)
214                CFPreferencesSetAppValue(DTS_PASSTHROUGH_KEY, (CFNumberRef)[NSNumber numberWithInt:1], PERIAN_DOMAIN);
215        else
216                CFPreferencesSetAppValue(DTS_PASSTHROUGH_KEY, (CFNumberRef)[NSNumber numberWithInt:0], PERIAN_DOMAIN);
217        soundState = (AC3PassthroughEnabled ? SOUND_STATE_AC3_PASSTHROUGH_WAS_ENABLED : 0) |
218                                 (soundsWereEnabled ? SOUND_STATE_SOUND_ENABLED : 0) |
219                                 (DTSPassthroughEnabled ? SOUND_STATE_DTS_PASSTHROUGH_WAS_ENABLED : 0);
220        CFPreferencesAppSynchronize(A52_DOMIAN);
221        CFPreferencesAppSynchronize(PERIAN_DOMAIN);
222        return soundState;
223}
224
225void teardownPassthrough(int soundState)
226{
227        if(soundState & SOUND_STATE_PLAYER_TORNDOWN)
228                return;
229       
230        soundState |= SOUND_STATE_PLAYER_TORNDOWN;
231        //Turn off the AC3 Passthrough hack
232        CFPreferencesSetAppValue(PASSTHROUGH_KEY, (CFNumberRef)[NSNumber numberWithInt:((soundState & SOUND_STATE_AC3_PASSTHROUGH_WAS_ENABLED)? 1 : 0)], A52_DOMIAN);
233        CFPreferencesAppSynchronize(A52_DOMIAN);
234        CFPreferencesSetAppValue(DTS_PASSTHROUGH_KEY, (CFNumberRef)[NSNumber numberWithInt:((soundState & SOUND_STATE_DTS_PASSTHROUGH_WAS_ENABLED)? 1 : 0)], PERIAN_DOMAIN);
235        CFPreferencesAppSynchronize(PERIAN_DOMAIN);
236        if(soundState & SOUND_STATE_SOUND_ENABLED)
237                [[SapphireFrontRowCompat sharedFrontRowPreferences] setBool:YES forKey:@"PlayFrontRowSounds"];
238       
239}
240
241- (void)setPlayFile:(SapphireFileMetaData *)file
242{
243        currentPlayFile = [file retain];
244        soundState = enablePassthrough(currentPlayFile);
245}
246
247- (void)teardownPlayback
248{
249        teardownPassthrough(soundState);
250        /*resume time*/
251        BRVideoPlayer *player = [self player];
252        float elapsed = [player elapsedPlaybackTime];
253        float duration = [player trackDuration];
254        if(duration == 0.0f)
255                elapsed = duration = 1.0f;
256
257        /*Get the resume time to save*/
258        if(elapsed < duration - 2)
259                [currentPlayFile setResumeTimeValue:elapsed];
260        else
261                [currentPlayFile setResumeTime:nil];
262       
263        if(elapsed / duration > 0.9f)
264        /*Mark as watched and reload info*/
265                [currentPlayFile setWatchedValue:YES];
266        [SapphireMetaDataSupport save:[currentPlayFile managedObjectContext]];
267}
268
269- (void)willBePopped
270{
271        [self teardownPlayback];
272        [super willBePopped];
273}
274
275- (void)wasPopped
276{
277        [self teardownPlayback];
278        [super wasPopped];
279}
280
281@end
Note: See TracBrowser for help on using the repository browser.