Skip to content

Latest commit

 

History

History
774 lines (663 loc) · 24.9 KB

coreaudio.c

File metadata and controls

774 lines (663 loc) · 24.9 KB
 
Oct 11, 2010
Oct 11, 2010
1
2
/*
* SDL_sound Core Audio backend
Oct 24, 2010
Oct 24, 2010
3
* Copyright (C) 2010 Eric Wing <ewing . public @ playcontrol.net>
Oct 11, 2010
Oct 11, 2010
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
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef SOUND_SUPPORTS_COREAUDIO
#include <stddef.h> /* NULL */
#include <stdio.h> /* printf */
#include <arpa/inet.h> /* htonl */
#include <AudioToolbox/AudioToolbox.h>
#include "SDL_sound.h"
#define __SDL_SOUND_INTERNAL__
#include "SDL_sound_internal.h"
typedef struct CoreAudioFileContainer
{
AudioFileID* audioFileID;
ExtAudioFileRef extAudioFileRef;
AudioStreamBasicDescription* outputFormat;
} CoreAudioFileContainer;
static int CoreAudio_init(void);
static void CoreAudio_quit(void);
static int CoreAudio_open(Sound_Sample *sample, const char *ext);
static void CoreAudio_close(Sound_Sample *sample);
static Uint32 CoreAudio_read(Sound_Sample *sample);
static int CoreAudio_rewind(Sound_Sample *sample);
static int CoreAudio_seek(Sound_Sample *sample, Uint32 ms);
static const char *extensions_coreaudio[] =
{
"aif",
"aiff",
"aifc",
"wav",
"wave",
"mp3",
"mp4",
"m4a",
"aac",
"caf",
"Sd2f",
Oct 24, 2010
Oct 24, 2010
64
"Sd2",
Oct 11, 2010
Oct 11, 2010
65
66
67
68
69
70
71
72
"au",
"next",
"mp2",
"mp1",
"ac3",
"3gpp",
"3gp2",
"amrf",
Oct 24, 2010
Oct 24, 2010
73
74
75
"amr",
"ima4",
"ima",
Oct 11, 2010
Oct 11, 2010
76
77
78
79
80
81
82
NULL
};
const Sound_DecoderFunctions __Sound_DecoderFunctions_CoreAudio =
{
{
extensions_coreaudio,
"Decode audio through Core Audio through",
Oct 24, 2010
Oct 24, 2010
83
"Eric Wing <ewing . public @ playcontrol.net>",
Oct 11, 2010
Oct 11, 2010
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
"http://playcontrol.net"
},
CoreAudio_init, /* init() method */
CoreAudio_quit, /* quit() method */
CoreAudio_open, /* open() method */
CoreAudio_close, /* close() method */
CoreAudio_read, /* read() method */
CoreAudio_rewind, /* rewind() method */
CoreAudio_seek /* seek() method */
};
static int CoreAudio_init(void)
{
return(1); /* always succeeds. */
} /* CoreAudio_init */
static void CoreAudio_quit(void)
{
/* it's a no-op. */
} /* CoreAudio_quit */
Oct 24, 2010
Oct 24, 2010
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/*
http://developer.apple.com/library/ios/#documentation/MusicAudio/Reference/AudioFileConvertRef/Reference/reference.html
kAudioFileAIFFType = 'AIFF',
kAudioFileAIFCType = 'AIFC',
kAudioFileWAVEType = 'WAVE',
kAudioFileSoundDesigner2Type = 'Sd2f',
kAudioFileNextType = 'NeXT',
kAudioFileMP3Type = 'MPG3',
kAudioFileMP2Type = 'MPG2',
kAudioFileMP1Type = 'MPG1',
kAudioFileAC3Type = 'ac-3',
kAudioFileAAC_ADTSType = 'adts',
kAudioFileMPEG4Type = 'mp4f',
kAudioFileM4AType = 'm4af',
kAudioFileCAFType = 'caff',
kAudioFile3GPType = '3gpp',
kAudioFile3GP2Type = '3gp2',
kAudioFileAMRType = 'amrf'
*/
Oct 11, 2010
Oct 11, 2010
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
static AudioFileTypeID CoreAudio_GetAudioTypeForExtension(const char* file_extension)
{
if( (__Sound_strcasecmp(file_extension, "aif") == 0)
|| (__Sound_strcasecmp(file_extension, "aiff") == 0)
|| (__Sound_strcasecmp(file_extension, "aifc") == 0)
)
{
return kAudioFileAIFCType;
}
else if( (__Sound_strcasecmp(file_extension, "wav") == 0)
|| (__Sound_strcasecmp(file_extension, "wave") == 0)
)
{
return kAudioFileWAVEType;
}
else if( (__Sound_strcasecmp(file_extension, "mp3") == 0)
)
{
return kAudioFileMP3Type;
}
else if( (__Sound_strcasecmp(file_extension, "mp4") == 0)
)
{
return kAudioFileMPEG4Type;
}
else if( (__Sound_strcasecmp(file_extension, "m4a") == 0)
)
{
return kAudioFileM4AType;
}
else if( (__Sound_strcasecmp(file_extension, "aac") == 0)
)
{
return kAudioFileAAC_ADTSType;
}
else if( (__Sound_strcasecmp(file_extension, "aac") == 0)
)
{
return kAudioFileAAC_ADTSType;
}
else if( (__Sound_strcasecmp(file_extension, "caf") == 0)
|| (__Sound_strcasecmp(file_extension, "caff") == 0)
)
{
return kAudioFileCAFType;
}
else if( (__Sound_strcasecmp(file_extension, "Sd2f") == 0)
Oct 24, 2010
Oct 24, 2010
174
|| (__Sound_strcasecmp(file_extension, "sd2") == 0)
Oct 11, 2010
Oct 11, 2010
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
)
{
return kAudioFileSoundDesigner2Type;
}
else if( (__Sound_strcasecmp(file_extension, "au") == 0)
|| (__Sound_strcasecmp(file_extension, "next") == 0)
)
{
return kAudioFileNextType;
}
else if( (__Sound_strcasecmp(file_extension, "mp2") == 0)
)
{
return kAudioFileMP2Type;
}
else if( (__Sound_strcasecmp(file_extension, "mp1") == 0)
)
{
return kAudioFileMP1Type;
}
else if( (__Sound_strcasecmp(file_extension, "ac3") == 0)
)
{
return kAudioFileAC3Type;
}
else if( (__Sound_strcasecmp(file_extension, "3gpp") == 0)
)
{
return kAudioFile3GPType;
}
else if( (__Sound_strcasecmp(file_extension, "3gp2") == 0)
)
{
return kAudioFile3GP2Type;
}
else if( (__Sound_strcasecmp(file_extension, "amrf") == 0)
Oct 24, 2010
Oct 24, 2010
211
|| (__Sound_strcasecmp(file_extension, "amr") == 0)
Oct 11, 2010
Oct 11, 2010
212
213
214
215
)
{
return kAudioFileAMRType;
}
Oct 24, 2010
Oct 24, 2010
216
217
218
219
220
221
222
else if( (__Sound_strcasecmp(file_extension, "ima4") == 0)
|| (__Sound_strcasecmp(file_extension, "ima") == 0)
)
{
/* not sure about this one */
return kAudioFileCAFType;
}
Oct 11, 2010
Oct 11, 2010
223
224
225
226
else
{
return 0;
}
Oct 24, 2010
Oct 24, 2010
227
Oct 11, 2010
Oct 11, 2010
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
}
static const char* CoreAudio_FourCCToString(int32_t error_code)
{
static char return_string[16];
uint32_t big_endian_code = htonl(error_code);
char* big_endian_str = (char*)&big_endian_code;
// see if it appears to be a 4-char-code
if(isprint(big_endian_str[0])
&& isprint(big_endian_str[1])
&& isprint(big_endian_str[2])
&& isprint (big_endian_str[3]))
{
return_string[0] = '\'';
return_string[1] = big_endian_str[0];
return_string[2] = big_endian_str[1];
return_string[3] = big_endian_str[2];
return_string[4] = big_endian_str[3];
return_string[5] = '\'';
return_string[6] = '\0';
}
else if(error_code > -200000 && error_code < 200000)
{
// no, format it as an integer
snprintf(return_string, 16, "%d", error_code);
}
else
{
// no, format it as an integer but in hex
snprintf(return_string, 16, "0x%x", error_code);
}
return return_string;
}
SInt64 CoreAudio_SizeCallback(void* inClientData)
{
SDL_RWops* rw_ops = (SDL_RWops*)inClientData;
SInt64 current_position = SDL_RWtell(rw_ops);
SInt64 end_position = SDL_RWseek(rw_ops, 0, SEEK_END);
SDL_RWseek(rw_ops, current_position, SEEK_SET);
// fprintf(stderr, "CoreAudio_SizeCallback:%d\n", end_position);
return end_position;
}
OSStatus CoreAudio_ReadCallback(
void* inClientData,
SInt64 inPosition,
UInt32 requestCount,
void* data_buffer,
UInt32* actualCount
)
{
SDL_RWops* rw_ops = (SDL_RWops*)inClientData;
SDL_RWseek(rw_ops, inPosition, SEEK_SET);
size_t bytes_actually_read = SDL_RWread(rw_ops, data_buffer, 1, requestCount);
// Not sure how to test for a read error with SDL_RWops
// fprintf(stderr, "CoreAudio_ReadCallback:%d, %d\n", requestCount, bytes_actually_read);
*actualCount = bytes_actually_read;
return noErr;
}
static int CoreAudio_open(Sound_Sample *sample, const char *ext)
{
CoreAudioFileContainer* core_audio_file_container;
AudioFileID* audio_file_id;
OSStatus error_result;
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
AudioStreamBasicDescription actual_format;
AudioStreamBasicDescription output_format;
Float64 estimated_duration;
UInt32 format_size;
core_audio_file_container = (CoreAudioFileContainer*)malloc(sizeof(CoreAudioFileContainer));
BAIL_IF_MACRO(core_audio_file_container == NULL, ERR_OUT_OF_MEMORY, 0);
audio_file_id = (AudioFileID*)malloc(sizeof(AudioFileID));
BAIL_IF_MACRO(audio_file_id == NULL, ERR_OUT_OF_MEMORY, 0);
error_result = AudioFileOpenWithCallbacks(
internal->rw,
CoreAudio_ReadCallback,
NULL,
CoreAudio_SizeCallback,
NULL,
CoreAudio_GetAudioTypeForExtension(ext),
audio_file_id
);
if (error_result != noErr)
{
AudioFileClose(*audio_file_id);
free(audio_file_id);
free(core_audio_file_container);
SNDDBG(("Core Audio: can't grok data. reason: [%s].\n", CoreAudio_FourCCToString(error_result)));
BAIL_MACRO("Core Audio: Not valid audio data.", 0);
} /* if */
format_size = sizeof(actual_format);
error_result = AudioFileGetProperty(
*audio_file_id,
kAudioFilePropertyDataFormat,
&format_size,
&actual_format
);
if (error_result != noErr)
{
AudioFileClose(*audio_file_id);
free(audio_file_id);
free(core_audio_file_container);
Oct 24, 2010
Oct 24, 2010
343
SNDDBG(("Core Audio: AudioFileGetProperty failed. reason: [%s]", CoreAudio_FourCCToString(error_result)));
Oct 11, 2010
Oct 11, 2010
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
BAIL_MACRO("Core Audio: Not valid audio data.", 0);
} /* if */
format_size = sizeof(estimated_duration);
error_result = AudioFileGetProperty(
*audio_file_id,
kAudioFilePropertyEstimatedDuration,
&format_size,
&estimated_duration
);
if (error_result != noErr)
{
AudioFileClose(*audio_file_id);
free(audio_file_id);
free(core_audio_file_container);
SNDDBG(("Core Audio: AudioFileGetProperty failed. reason: [%s].\n", CoreAudio_FourCCToString(error_result)));
BAIL_MACRO("Core Audio: Not valid audio data.", 0);
} /* if */
core_audio_file_container->audioFileID = audio_file_id;
internal->decoder_private = core_audio_file_container;
sample->flags = SOUND_SAMPLEFLAG_CANSEEK;
Oct 24, 2010
Oct 24, 2010
369
370
371
sample->actual.rate = (UInt32) actual_format.mSampleRate;
sample->actual.channels = (UInt8)actual_format.mChannelsPerFrame;
internal->total_time = (SInt32)(estimated_duration * 1000.0 + 0.5);
Oct 11, 2010
Oct 11, 2010
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
#if 0
/* FIXME: Both Core Audio and SDL 1.3 support float and 32-bit formats */
if(actual_format.mFormatFlags & kAudioFormatFlagIsBigEndian)
{
if(16 == actual_format.mBitsPerChannel)
{
if(kAudioFormatFlagIsSignedInteger & actual_format.mFormatFlags)
{
sample->actual.format = AUDIO_S16MSB;
}
else
{
sample->actual.format = AUDIO_U16MSB;
}
}
else if(8 == actual_format.mBitsPerChannel)
{
if(kAudioFormatFlagIsSignedInteger & actual_format.mFormatFlags)
{
sample->actual.format = AUDIO_S8;
}
else
{
sample->actual.format = AUDIO_U8;
}
}
else // might be 0 for undefined?
{
// This case seems to come up a lot for me. Maybe for file types like .m4a?
sample->actual.format = AUDIO_S16SYS;
SNDDBG(("Core Audio: Unsupported actual_format.mBitsPerChannel: [%d].\n", actual_format.mBitsPerChannel));
}
}
else // little endian
{
if(16 == actual_format.mBitsPerChannel)
{
if(kAudioFormatFlagIsSignedInteger & actual_format.mFormatFlags)
{
sample->actual.format = AUDIO_S16LSB;
}
else
{
sample->actual.format = AUDIO_U16LSB;
}
}
else if(8 == actual_format.mBitsPerChannel)
{
if(kAudioFormatFlagIsSignedInteger & actual_format.mFormatFlags)
{
sample->actual.format = AUDIO_S8;
}
else
{
sample->actual.format = AUDIO_U8;
}
}
else // might be 0 for undefined?
{
sample->actual.format = AUDIO_S16SYS;
SNDDBG(("Core Audio: Unsupported actual_format.mBitsPerChannel: [%d].\n", actual_format.mBitsPerChannel));
}
}
#else
/*
* I want to use Core Audio to do conversion and decoding for performance reasons.
* This is particularly important on mobile devices like iOS.
* Taking from the Ogg Vorbis decode, I pretend the "actual" format is the same
* as the desired format.
*/
sample->actual.format = (sample->desired.format == 0) ?
AUDIO_S16SYS : sample->desired.format;
#endif
SNDDBG(("CoreAudio: channels == (%d).\n", sample->actual.channels));
SNDDBG(("CoreAudio: sampling rate == (%d).\n",sample->actual.rate));
SNDDBG(("CoreAudio: total seconds of sample == (%d).\n", internal->total_time));
SNDDBG(("CoreAudio: sample->actual.format == (%d).\n", sample->actual.format));
error_result = ExtAudioFileWrapAudioFileID(*audio_file_id,
false, // set to false for read-only
&core_audio_file_container->extAudioFileRef
);
if(error_result != noErr)
{
AudioFileClose(*audio_file_id);
free(audio_file_id);
free(core_audio_file_container);
SNDDBG(("Core Audio: can't wrap data. reason: [%s].\n", CoreAudio_FourCCToString(error_result)));
BAIL_MACRO("Core Audio: Failed to wrap data.", 0);
} /* if */
/* The output format must be linear PCM because that's the only type OpenAL knows how to deal with.
* Set the client format to 16 bit signed integer (native-endian) data because that is the most
* optimal format on iPhone/iPod Touch hardware.
* Maintain the channel count and sample rate of the original source format.
*/
output_format.mSampleRate = actual_format.mSampleRate; // preserve the original sample rate
output_format.mChannelsPerFrame = actual_format.mChannelsPerFrame; // preserve the number of channels
output_format.mFormatID = kAudioFormatLinearPCM; // We want linear PCM data
output_format.mFramesPerPacket = 1; // We know for linear PCM, the definition is 1 frame per packet
if(sample->desired.format == 0)
{
// do AUDIO_S16SYS
Oct 24, 2010
Oct 24, 2010
488
output_format.mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; // I seem to read failures problems without kAudioFormatFlagIsPacked. From a mailing list post, this seems to be a Core Audio bug.
Oct 11, 2010
Oct 11, 2010
489
490
491
492
493
output_format.mBitsPerChannel = 16; // We know we want 16-bit
}
else
{
output_format.mFormatFlags = 0; // clear flags
Oct 24, 2010
Oct 24, 2010
494
output_format.mFormatFlags |= kAudioFormatFlagIsPacked; // I seem to read failures problems without kAudioFormatFlagIsPacked. From a mailing list post, this seems to be a Core Audio bug.
Oct 11, 2010
Oct 11, 2010
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
// Mask against bitsize
if(0xFF & sample->desired.format)
{
output_format.mBitsPerChannel = 16; /* 16-bit */
}
else
{
output_format.mBitsPerChannel = 8; /* 8-bit */
}
// Mask for signed/unsigned
if((1<<15) & sample->desired.format)
{
output_format.mFormatFlags = output_format.mFormatFlags | kAudioFormatFlagIsSignedInteger;
}
else
{
// no flag set for unsigned
}
// Mask for big/little endian
if((1<<12) & sample->desired.format)
{
output_format.mFormatFlags = output_format.mFormatFlags | kAudioFormatFlagIsBigEndian;
}
else
{
// no flag set for little endian
}
}
output_format.mBytesPerPacket = output_format.mBitsPerChannel/8 * output_format.mChannelsPerFrame; // e.g. 16-bits/8 * channels => so 2-bytes per channel per frame
output_format.mBytesPerFrame = output_format.mBitsPerChannel/8 * output_format.mChannelsPerFrame; // For PCM, since 1 frame is 1 packet, it is the same as mBytesPerPacket
/*
output_format.mSampleRate = actual_format.mSampleRate; // preserve the original sample rate
output_format.mChannelsPerFrame = actual_format.mChannelsPerFrame; // preserve the number of channels
output_format.mFormatID = kAudioFormatLinearPCM; // We want linear PCM data
// output_format.mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger;
output_format.mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsSignedInteger;
output_format.mFramesPerPacket = 1; // We know for linear PCM, the definition is 1 frame per packet
output_format.mBitsPerChannel = 16; // We know we want 16-bit
output_format.mBytesPerPacket = 2 * output_format.mChannelsPerFrame; // We know we are using 16-bit, so 2-bytes per channel per frame
output_format.mBytesPerFrame = 2 * output_format.mChannelsPerFrame; // For PCM, since 1 frame is 1 packet, it is the same as mBytesPerPacket
*/
SNDDBG(("output_format: mSampleRate: %lf\n", output_format.mSampleRate));
SNDDBG(("output_format: mChannelsPerFrame: %d\n", output_format.mChannelsPerFrame));
SNDDBG(("output_format: mFormatID: %d\n", output_format.mFormatID));
SNDDBG(("output_format: mFormatFlags: %d\n", output_format.mFormatFlags));
SNDDBG(("output_format: mFramesPerPacket: %d\n", output_format.mFramesPerPacket));
SNDDBG(("output_format: mBitsPerChannel: %d\n", output_format.mBitsPerChannel));
SNDDBG(("output_format: mBytesPerPacket: %d\n", output_format.mBytesPerPacket));
SNDDBG(("output_format: mBytesPerFrame: %d\n", output_format.mBytesPerFrame));
/* Set the desired client (output) data format */
error_result = ExtAudioFileSetProperty(core_audio_file_container->extAudioFileRef, kExtAudioFileProperty_ClientDataFormat, sizeof(output_format), &output_format);
if(noErr != error_result)
{
ExtAudioFileDispose(core_audio_file_container->extAudioFileRef);
AudioFileClose(*audio_file_id);
free(audio_file_id);
free(core_audio_file_container);
SNDDBG(("Core Audio: ExtAudioFileSetProperty(kExtAudioFileProperty_ClientDataFormat) failed, reason: [%s].\n", CoreAudio_FourCCToString(error_result)));
BAIL_MACRO("Core Audio: Not valid audio data.", 0);
}
core_audio_file_container->outputFormat = (AudioStreamBasicDescription*)malloc(sizeof(AudioStreamBasicDescription));
BAIL_IF_MACRO(core_audio_file_container->outputFormat == NULL, ERR_OUT_OF_MEMORY, 0);
/* Copy the output format to the audio_description that was passed in so the
* info will be returned to the user.
*/
memcpy(core_audio_file_container->outputFormat, &output_format, sizeof(AudioStreamBasicDescription));
return(1);
} /* CoreAudio_open */
static void CoreAudio_close(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
CoreAudioFileContainer* core_audio_file_container = (CoreAudioFileContainer *) internal->decoder_private;
Nov 6, 2010
Nov 6, 2010
585
free(core_audio_file_container->outputFormat);
Oct 11, 2010
Oct 11, 2010
586
587
588
589
590
591
592
593
594
595
596
ExtAudioFileDispose(core_audio_file_container->extAudioFileRef);
AudioFileClose(*core_audio_file_container->audioFileID);
free(core_audio_file_container->audioFileID);
free(core_audio_file_container);
} /* CoreAudio_close */
static Uint32 CoreAudio_read(Sound_Sample *sample)
{
OSStatus error_result = noErr;
Oct 24, 2010
Oct 24, 2010
597
598
599
600
601
602
603
604
605
606
/* Documentation/example shows SInt64, but is problematic for big endian
* on 32-bit cast for ExtAudioFileRead() because it takes the upper
* bits which turn to 0.
*/
UInt32 buffer_size_in_frames = 0;
UInt32 buffer_size_in_frames_remaining = 0;
UInt32 total_frames_read = 0;
UInt32 data_buffer_size = 0;
UInt32 bytes_remaining = 0;
size_t total_bytes_read = 0;
Oct 11, 2010
Oct 11, 2010
607
608
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
CoreAudioFileContainer* core_audio_file_container = (CoreAudioFileContainer *) internal->decoder_private;
Oct 24, 2010
Oct 24, 2010
609
UInt32 max_buffer_size = internal->buffer_size;
Oct 11, 2010
Oct 11, 2010
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
// printf("internal->buffer_size=%d, internal->buffer=0x%x, sample->buffer_size=%d\n", internal->buffer_size, internal->buffer, sample->buffer_size);
// printf("internal->max_buffer_size=%d\n", max_buffer_size);
/* Compute how many frames will fit into our max buffer size */
/* Warning: If this is not evenly divisible, the buffer will not be completely filled which violates the SDL_sound assumption. */
buffer_size_in_frames = max_buffer_size / core_audio_file_container->outputFormat->mBytesPerFrame;
// printf("buffer_size_in_frames=%ld, internal->buffer_size=%d, internal->buffer=0x%x outputFormat->mBytesPerFrame=%d, sample->buffer_size=%d\n", buffer_size_in_frames, internal->buffer_size, internal->buffer, core_audio_file_container->outputFormat->mBytesPerFrame, sample->buffer_size);
// void* temp_buffer = malloc(max_buffer_size);
AudioBufferList audio_buffer_list;
audio_buffer_list.mNumberBuffers = 1;
audio_buffer_list.mBuffers[0].mDataByteSize = max_buffer_size;
audio_buffer_list.mBuffers[0].mNumberChannels = core_audio_file_container->outputFormat->mChannelsPerFrame;
audio_buffer_list.mBuffers[0].mData = internal->buffer;
bytes_remaining = max_buffer_size;
buffer_size_in_frames_remaining = buffer_size_in_frames;
Oct 24, 2010
Oct 24, 2010
632
633
634
635
636
637
638
// oops. Due to the kAudioFormatFlagIsPacked bug,
// I was misled to believe that Core Audio
// was not always filling my entire requested buffer.
// So this while-loop might be unnecessary.
// However, I have not exhaustively tested all formats,
// so maybe it is possible this loop is useful.
// It might also handle the not-evenly disvisible case above.
Oct 11, 2010
Oct 11, 2010
639
640
641
while(buffer_size_in_frames_remaining > 0 && !(sample->flags & SOUND_SAMPLEFLAG_EOF))
{
Oct 24, 2010
Oct 24, 2010
642
data_buffer_size = (UInt32)(buffer_size_in_frames * core_audio_file_container->outputFormat->mBytesPerFrame);
Oct 11, 2010
Oct 11, 2010
643
644
645
646
647
648
649
650
// printf("data_buffer_size=%d\n", data_buffer_size);
buffer_size_in_frames = buffer_size_in_frames_remaining;
// printf("reading buffer_size_in_frames=%"PRId64"\n", buffer_size_in_frames);
audio_buffer_list.mBuffers[0].mDataByteSize = bytes_remaining;
Oct 24, 2010
Oct 24, 2010
651
audio_buffer_list.mBuffers[0].mData = &(((UInt8*)internal->buffer)[total_bytes_read]);
Oct 11, 2010
Oct 11, 2010
652
653
654
/* Read the data into an AudioBufferList */
Oct 24, 2010
Oct 24, 2010
655
error_result = ExtAudioFileRead(core_audio_file_container->extAudioFileRef, &buffer_size_in_frames, &audio_buffer_list);
Oct 11, 2010
Oct 11, 2010
656
657
658
659
660
661
662
663
664
if(error_result == noErr)
{
/* Success */
total_frames_read += buffer_size_in_frames;
buffer_size_in_frames_remaining = buffer_size_in_frames_remaining - buffer_size_in_frames;
Oct 24, 2010
Oct 24, 2010
665
// printf("read buffer_size_in_frames=%"PRId64", buffer_size_in_frames_remaining=%"PRId64"\n", buffer_size_in_frames, buffer_size_in_frames_remaining);
Oct 11, 2010
Oct 11, 2010
666
667
/* ExtAudioFileRead returns the number of frames actually read. Need to convert back to bytes. */
Oct 24, 2010
Oct 24, 2010
668
data_buffer_size = (UInt32)(buffer_size_in_frames * core_audio_file_container->outputFormat->mBytesPerFrame);
Oct 11, 2010
Oct 11, 2010
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
// printf("data_buffer_size=%d\n", data_buffer_size);
total_bytes_read += data_buffer_size;
bytes_remaining = bytes_remaining - data_buffer_size;
/* Note: 0 == buffer_size_in_frames is a legitimate value meaning we are EOF. */
if(0 == buffer_size_in_frames)
{
sample->flags |= SOUND_SAMPLEFLAG_EOF;
}
}
else
{
SNDDBG(("Core Audio: ExtAudioFileReadfailed, reason: [%s].\n", CoreAudio_FourCCToString(error_result)));
sample->flags |= SOUND_SAMPLEFLAG_ERROR;
break;
}
}
if( (!(sample->flags & SOUND_SAMPLEFLAG_EOF)) && (total_bytes_read < max_buffer_size))
{
SNDDBG(("Core Audio: ExtAudioFileReadfailed SOUND_SAMPLEFLAG_EAGAIN, reason: [total_bytes_read < max_buffer_size], %d, %d.\n", total_bytes_read , max_buffer_size));
Oct 24, 2010
Oct 24, 2010
695
/* Don't know what to do here. */
Oct 11, 2010
Oct 11, 2010
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
}
return total_bytes_read;
} /* CoreAudio_read */
static int CoreAudio_rewind(Sound_Sample *sample)
{
OSStatus error_result = noErr;
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
CoreAudioFileContainer* core_audio_file_container = (CoreAudioFileContainer *) internal->decoder_private;
error_result = ExtAudioFileSeek(core_audio_file_container->extAudioFileRef, 0);
if(error_result != noErr)
{
sample->flags |= SOUND_SAMPLEFLAG_ERROR;
}
return(1);
} /* CoreAudio_rewind */
Nov 9, 2010
Nov 9, 2010
716
717
718
719
720
/* Note: I found this tech note:
http://developer.apple.com/library/mac/#qa/qa2009/qa1678.html
I don't know if this applies to us. So far, I haven't noticed the problem,
so I haven't applied any of the techniques.
*/
Oct 11, 2010
Oct 11, 2010
721
722
723
724
725
726
727
728
729
static int CoreAudio_seek(Sound_Sample *sample, Uint32 ms)
{
OSStatus error_result = noErr;
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
CoreAudioFileContainer* core_audio_file_container = (CoreAudioFileContainer *) internal->decoder_private;
SInt64 frame_offset = 0;
AudioStreamBasicDescription actual_format;
UInt32 format_size;
Nov 9, 2010
Nov 9, 2010
730
731
732
733
734
735
736
737
738
739
/* I'm confused. The Apple documentation says this:
"Seek position is specified in the sample rate and frame count of the file’s audio data format
— not your application’s audio data format."
My interpretation is that I want to get the "actual format of the file and compute the frame offset.
But when I try that, seeking goes to the wrong place.
When I use outputFormat, things seem to work correctly.
I must be misinterpreting the documentation or doing something wrong.
*/
#if 0 /* not working */
Oct 11, 2010
Oct 11, 2010
740
741
742
743
744
745
746
747
748
749
750
751
752
753
format_size = sizeof(AudioStreamBasicDescription);
error_result = AudioFileGetProperty(
*core_audio_file_container->audioFileID,
kAudioFilePropertyDataFormat,
&format_size,
&actual_format
);
if(error_result != noErr)
{
sample->flags |= SOUND_SAMPLEFLAG_ERROR;
BAIL_MACRO("Core Audio: Could not GetProperty for kAudioFilePropertyDataFormat.", 0);
} /* if */
// packetIndex = (pos * sampleRate) / framesPerPacket
Nov 9, 2010
Nov 9, 2010
754
755
756
757
758
759
// frame_offset = (SInt64)((ms/1000.0 * actual_format.mSampleRate) / actual_format.mFramesPerPacket);
#else /* seems to work, but I'm confused */
// packetIndex = (pos * sampleRate) / framesPerPacket
frame_offset = (SInt64)((ms/1000.0 * core_audio_file_container->outputFormat->mSampleRate) / core_audio_file_container->outputFormat->mFramesPerPacket);
#endif
Oct 11, 2010
Oct 11, 2010
760
761
762
763
764
765
766
767
768
769
770
771
772
// computed against actual format and not the client format
error_result = ExtAudioFileSeek(core_audio_file_container->extAudioFileRef, frame_offset);
if(error_result != noErr)
{
sample->flags |= SOUND_SAMPLEFLAG_ERROR;
}
return(1);
} /* CoreAudio_seek */
#endif /* SOUND_SUPPORTS_COREAUDIO */
Oct 24, 2010
Oct 24, 2010
773
/* end of coreaudio.c ... */