Subversion Repositories Mobile Apps.GyroMouse

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
//
2
//  ISSoundAdditions.m (ver 1.2 - 2012.10.27)
3
//
4
//      Created by Massimo Moiso (2012-09) InerziaSoft
5
//      based on an idea of Antonio Nunes, SintraWorks
6
//
7
// Permission is granted free of charge to use this code without restriction
8
// and without limitation, with the only condition that the copyright
9
// notice and this permission shall be included in all copies.
10
//
11
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
17
// THE SOFTWARE.
18
 
19
 
20
#import "ISSoundAdditions.h"
21
 
22
AudioDeviceID obtainDefaultOutputDevice (void);
23
 
24
@implementation NSSound (ISSoundAdditions)
25
 
26
//
27
//      Return the ID of the default audio device; this is a C routine
28
//
29
//      IN:             none
30
//      OUT:    the ID of the default device or AudioObjectUnknown
31
//
32
AudioDeviceID obtainDefaultOutputDevice (void)
33
{
34
    AudioDeviceID theAnswer = kAudioObjectUnknown;
35
    UInt32 theSize = sizeof(AudioDeviceID);
36
    AudioObjectPropertyAddress theAddress;
37
 
38
        theAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
39
        theAddress.mScope = kAudioObjectPropertyScopeGlobal;
40
        theAddress.mElement = kAudioObjectPropertyElementMaster;
41
 
42
        //first be sure that a default device exists
43
        if (! AudioObjectHasProperty(kAudioObjectSystemObject, &theAddress) )   {
44
                NSLog(@"Unable to get default audio device");
45
                return theAnswer;
46
        }
47
        //get the property 'default output device'
48
    OSStatus theError = AudioObjectGetPropertyData(kAudioObjectSystemObject, &theAddress, 0, NULL, &theSize, &theAnswer);
49
    if (theError != noErr) {
50
                NSLog(@"Unable to get output audio device");
51
                return theAnswer;
52
        }
53
    return theAnswer;
54
}
55
 
56
//
57
//      Return the ID of the default audio device; this is a category class method
58
//      that can be called from outside
59
//
60
//      IN:             none
61
//      OUT:    the ID of the default device or AudioObjectUnknown
62
//
63
+ (AudioDeviceID)defaultOutputDevice
64
{
65
        return obtainDefaultOutputDevice();
66
}
67
 
68
 
69
//
70
//      Return the system sound volume as a float in the range [0...1]
71
//
72
//      IN:             none
73
//      OUT:    (float) the volume of the default device
74
//
75
+ (float)systemVolume
76
{      
77
        AudioDeviceID                           defaultDevID = kAudioObjectUnknown;
78
        UInt32                                          theSize = sizeof(Float32);
79
        OSStatus                                        theError;
80
        Float32                                         theVolume = 0;
81
        AudioObjectPropertyAddress      theAddress;
82
 
83
        defaultDevID = obtainDefaultOutputDevice();
84
        if (defaultDevID == kAudioObjectUnknown) return 0.0;            //device not found: return 0
85
 
86
        theAddress.mSelector = kAudioHardwareServiceDeviceProperty_VirtualMainVolume;
87
        theAddress.mScope = kAudioDevicePropertyScopeOutput;
88
        theAddress.mElement = kAudioObjectPropertyElementMaster;
89
 
90
        //be sure that the default device has the volume property
91
        if (! AudioObjectHasProperty(defaultDevID, &theAddress) ) {
92
                NSLog(@"No volume control for device 0x%0x",defaultDevID);
93
                return 0.0;
94
        }
95
 
96
        //now read the property and correct it, if outside [0...1]
97
        theError = AudioObjectGetPropertyData(defaultDevID, &theAddress, 0, NULL, &theSize, &theVolume);
98
        if ( theError != noErr )        {
99
                NSLog(@"Unable to read volume for device 0x%0x", defaultDevID);
100
                return 0.0;
101
        }
102
        theVolume = theVolume > 1.0 ? 1.0 : (theVolume < 0.0 ? 0.0 : theVolume);
103
 
104
        return theVolume;
105
}
106
 
107
//
108
//      Set the volume of the default device
109
//
110
//      IN:             (float)the new volume
111
//      OUT:    none
112
//
113
+ (void)setSystemVolume:(float)theVolume
114
{
115
        float                                           newValue = theVolume;
116
        AudioObjectPropertyAddress      theAddress;
117
        AudioDeviceID                           defaultDevID;
118
        OSStatus                                        theError = noErr;
119
        UInt32                                          muted;
120
        Boolean                                         canSetVol = YES, muteValue;
121
        Boolean                                         hasMute = YES, canMute = YES;
122
 
123
        defaultDevID = obtainDefaultOutputDevice();
124
        if (defaultDevID == kAudioObjectUnknown) {                      //device not found: return without trying to set
125
                NSLog(@"Device unknown");
126
                return;
127
        }
128
 
129
                //check if the new value is in the correct range - normalize it if not
130
        newValue = theVolume > 1.0 ? 1.0 : (theVolume < 0.0 ? 0.0 : theVolume);
131
        if (newValue != theVolume) {
132
                NSLog(@"Tentative volume (%5.2f) was out of range; reset to %5.2f", theVolume, newValue);
133
        }
134
 
135
        theAddress.mElement = kAudioObjectPropertyElementMaster;
136
        theAddress.mScope = kAudioDevicePropertyScopeOutput;
137
 
138
                //set the selector to mute or not by checking if under threshold and check if a mute command is available
139
        if ( (muteValue = (newValue < THRESHOLD)) )
140
        {
141
                theAddress.mSelector = kAudioDevicePropertyMute;
142
                hasMute = AudioObjectHasProperty(defaultDevID, &theAddress);
143
                if (hasMute)
144
                {
145
                        theError = AudioObjectIsPropertySettable(defaultDevID, &theAddress, &canMute);
146
                        if (theError != noErr || !canMute)
147
                        {
148
                                canMute = NO;
149
                                NSLog(@"Should mute device 0x%0x but did not success",defaultDevID);
150
                        }
151
                }
152
                else canMute = NO;
153
        }
154
        else
155
        {
156
                theAddress.mSelector = kAudioHardwareServiceDeviceProperty_VirtualMainVolume;
157
        }
158
 
159
// **** now manage the volume following the what we found ****
160
 
161
                //be sure the device has a volume command
162
        if (! AudioObjectHasProperty(defaultDevID, &theAddress))
163
        {
164
                NSLog(@"The device 0x%0x does not have a volume to set", defaultDevID);
165
                return;
166
        }
167
 
168
                //be sure the device can set the volume
169
        theError = AudioObjectIsPropertySettable(defaultDevID, &theAddress, &canSetVol);
170
        if ( theError!=noErr || !canSetVol )
171
        {
172
                NSLog(@"The volume of device 0x%0x cannot be set", defaultDevID);
173
                return;
174
        }
175
 
176
                //if under the threshold then mute it, only if possible - done/exit
177
        if (muteValue && hasMute && canMute)
178
        {
179
                muted = 1;
180
                theError = AudioObjectSetPropertyData(defaultDevID, &theAddress, 0, NULL, sizeof(muted), &muted);
181
                if (theError != noErr)
182
                {
183
                        NSLog(@"The device 0x%0x was not muted",defaultDevID);
184
                        return;
185
                }
186
        }
187
        else            //else set it
188
        {
189
                theError = AudioObjectSetPropertyData(defaultDevID, &theAddress, 0, NULL, sizeof(newValue), &newValue);
190
                if (theError != noErr)
191
                {
192
                        NSLog(@"The device 0x%0x was unable to set volume", defaultDevID);
193
                }
194
                        //if device is able to handle muting, maybe it was muted, so unlock it
195
                if (hasMute && canMute)
196
                {
197
                        theAddress.mSelector = kAudioDevicePropertyMute;
198
                        muted = 0;
199
                        theError = AudioObjectSetPropertyData(defaultDevID, &theAddress, 0, NULL, sizeof(muted), &muted);
200
                }
201
        }
202
        if (theError != noErr) {
203
                NSLog(@"Unable to set volume for device 0x%0x", defaultDevID);
204
        }
205
}
206
 
207
 
208
//
209
//      Increase the volume of the system device by a certain value
210
//
211
//      IN:             (float) amount of volume to increase
212
//      OUT:    none
213
//
214
+ (void)increaseSystemVolumeBy:(float)amount {
215
    [self setSystemVolume:self.systemVolume+amount];
216
}
217
 
218
//
219
//      Decrease the volume of the system device by a certain value
220
//
221
//      IN:             (float) amount of volume to decrease
222
//      OUT:    none
223
//
224
+ (void)decreaseSystemVolumeBy:(float)amount {
225
    [self setSystemVolume:self.systemVolume-amount];
226
}
227
 
228
//
229
//      IN:             (Boolean) if true the device is muted, false it is unmated
230
//      OUT:            none
231
//
232
+ (void)applyMute:(Boolean)m
233
{
234
        AudioDeviceID                           defaultDevID = kAudioObjectUnknown;
235
        AudioObjectPropertyAddress      theAddress;
236
        Boolean                                         hasMute, canMute = YES;
237
        OSStatus                                        theError = noErr;
238
        UInt32                                          muted = 0;
239
 
240
        defaultDevID = obtainDefaultOutputDevice();
241
        if (defaultDevID == kAudioObjectUnknown) {                      //device not found
242
                NSLog(@"Device unknown");
243
                return;
244
        }
245
 
246
        theAddress.mElement = kAudioObjectPropertyElementMaster;
247
        theAddress.mScope = kAudioDevicePropertyScopeOutput;
248
        theAddress.mSelector = kAudioDevicePropertyMute;
249
        muted = m ? 1 : 0;
250
 
251
        hasMute = AudioObjectHasProperty(defaultDevID, &theAddress);
252
 
253
        if (hasMute)
254
        {
255
                theError = AudioObjectIsPropertySettable(defaultDevID, &theAddress, &canMute);
256
                if (theError == noErr && canMute)
257
                {
258
                        theError = AudioObjectSetPropertyData(defaultDevID, &theAddress, 0, NULL, sizeof(muted), &muted);
259
                        if (theError != noErr) NSLog(@"Cannot change mute status of device 0x%0x", defaultDevID);
260
                }
261
        }
262
}
263
 
264
@end