forked from alexwinston/ExternalAccessory
/
EAAudioPlayer.m
149 lines (118 loc) · 4.1 KB
/
EAAudioPlayer.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
//
// EAAudioPlayer.m
// ExternalAccessory
//
// Created by Alex Winston on 8/16/09.
// Copyright 2009 __MyCompanyName__. All rights reserved.
//
#import "EAAudioPlayer.h"
// EAAudioPlayer Singleton
static EAAudioPlayer *sharedAudioPlayer = nil;
@implementation EAAudioPlayer
+ (EAAudioPlayer *)sharedAudioPlayer {
@synchronized(self) {
if (sharedAudioPlayer == nil) {
[[self alloc] init]; // Assignment not done here
}
}
return sharedAudioPlayer;
}
+ (id)allocWithZone:(NSZone *)zone
{
@synchronized(self) {
if (sharedAudioPlayer == nil) {
sharedAudioPlayer = [super allocWithZone:zone];
return sharedAudioPlayer; // Assign and return on first allocation
}
}
return nil; // Subsequent allocation attempts return nil
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
static void AQBufferCallback(void *audioQueueData,
AudioQueueRef audioQueueRef,
AudioQueueBufferRef audioQueueBufferRef) {
EAAudioPlayer *audioPlayer = (EAAudioPlayer *)audioQueueData;
short *audioQueueBuffer = (short *)audioQueueBufferRef->mAudioData;
audioQueueBufferRef->mAudioDataByteSize = sizeof(short) * kAudioQueueBufferBytes;
for(int i = 0; i < kAudioQueueBufferBytes; i++) {
//float data = sinf((float)i * M_PI / 180.0f);
float data = [audioPlayer dequeueData];
data *= 32767.0f;
audioQueueBuffer[i] = (short)data;
}
AudioQueueEnqueueBuffer(audioQueueRef, audioQueueBufferRef, 0, NULL);
}
- (id)init {
if( !(self=[super init]) )
return nil;
// NSMutableArray that holds float data to be buffered for playback
audioData = [[NSMutableArray arrayWithCapacity:512] retain];
// AudioStreamBasicDescription audio format
audioFormat.mSampleRate = kAudioQueueSampleRate;
audioFormat.mFormatID = kAudioFormatLinearPCM;
audioFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; //| kAudioFormatFlagIsPacked;
audioFormat.mBytesPerPacket = 2;
audioFormat.mFramesPerPacket = 1;
audioFormat.mBytesPerFrame = 2;
audioFormat.mChannelsPerFrame = 1;
audioFormat.mBitsPerChannel = 16;
UInt32 err;
err = AudioQueueNewOutput(&audioFormat, AQBufferCallback, self, CFRunLoopGetMain(), kCFRunLoopCommonModes, 0, &audioQueue);
if (err) [NSException raise:@"AudioOutputError" format:@"AudioQueueNewOutput failed: %d", err];
err = AudioQueueSetParameter(audioQueue, kAudioQueueParam_Volume, 1.0);
if (err) [NSException raise:@"AudioOutputError" format:@"AudioQueueSetParameter failed: %d", err];
UInt32 bufferBytes = audioFormat.mBytesPerFrame * kAudioQueueBufferBytes;
for (int i = 0; i < kAudioQueueBufferRefCount; i++) {
UInt32 err = AudioQueueAllocateBuffer(audioQueue, bufferBytes, &audioQueueBuffers[i]);
if (err) [NSException raise:@"AudioOutputError" format:@"AudioQueueAllocateBuffer failed: %d", err];
}
return self;
}
- (void)start {
for (int i = 0; i < kAudioQueueBufferRefCount; i++) {
AQBufferCallback(self, audioQueue, audioQueueBuffers[i]);
}
UInt32 err = AudioQueueStart(audioQueue, NULL);
if (err) [NSException raise:@"AudioOutputError" format:@"AudioQueueStart failed: %d", err];
}
- (void)stop {
UInt32 err = AudioQueueStop(audioQueue, true);
if (err) [NSException raise:@"AudioOutputError" format:@"AudioQueueStop failed: %d", err];
}
- (float)dequeueData {
float data = 0.0f;
if ([audioData count] == 0)
return data;
id dataObject = [audioData objectAtIndex:0];
if (dataObject != nil) {
data = [dataObject floatValue];
//printf("%f\n", data);
[audioData removeObjectAtIndex:0];
}
return data;
}
- (void)enqueueData:(float)data {
// ???: NSLock
// TODO: Do not enqueueData if the player isn't started
[audioData addObject:[NSNumber numberWithFloat:data]];
}
- (id)retain {
return self;
}
- (unsigned)retainCount {
return UINT_MAX; // Denotes an object that cannot be released
}
- (void)release {
}
- (id)autorelease {
return self;
}
- (void)dealloc {
UInt32 err = AudioQueueDispose(audioQueue, true);
if (err) [NSException raise:@"AudioOutputError" format:@"AudioQueueDispose failed: %d", err];
[audioData release];
[super dealloc];
}
@end