comparison decoders/coreaudio.c @ 577:af33b35a55c1

Minor cleanups. Ready to release.
author Eric Wing <ewing . public |-at-| gmail . com>
date Sat, 23 Oct 2010 22:35:38 -0700
parents 8d62447b75f2
children 7ff36153215a
comparison
equal deleted inserted replaced
576:8d62447b75f2 577:af33b35a55c1
1 /* 1 /*
2 * SDL_sound Core Audio backend 2 * SDL_sound Core Audio backend
3 * Copyright (C) 2010 Eric Wing 3 * Copyright (C) 2010 Eric Wing <ewing . public @ playcontrol.net>
4 * 4 *
5 * This library is free software; you can redistribute it and/or 5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public 6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either 7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version. 8 * version 2.1 of the License, or (at your option) any later version.
38 AudioFileID* audioFileID; 38 AudioFileID* audioFileID;
39 ExtAudioFileRef extAudioFileRef; 39 ExtAudioFileRef extAudioFileRef;
40 AudioStreamBasicDescription* outputFormat; 40 AudioStreamBasicDescription* outputFormat;
41 } CoreAudioFileContainer; 41 } CoreAudioFileContainer;
42 42
43 //http://developer.apple.com/library/ios/#documentation/MusicAudio/Reference/AudioFileConvertRef/Reference/reference.html
44
45 static int CoreAudio_init(void); 43 static int CoreAudio_init(void);
46 static void CoreAudio_quit(void); 44 static void CoreAudio_quit(void);
47 static int CoreAudio_open(Sound_Sample *sample, const char *ext); 45 static int CoreAudio_open(Sound_Sample *sample, const char *ext);
48 static void CoreAudio_close(Sound_Sample *sample); 46 static void CoreAudio_close(Sound_Sample *sample);
49 static Uint32 CoreAudio_read(Sound_Sample *sample); 47 static Uint32 CoreAudio_read(Sound_Sample *sample);
61 "mp4", 59 "mp4",
62 "m4a", 60 "m4a",
63 "aac", 61 "aac",
64 "caf", 62 "caf",
65 "Sd2f", 63 "Sd2f",
64 "Sd2",
66 "au", 65 "au",
67 "next", 66 "next",
68 "mp2", 67 "mp2",
69 "mp1", 68 "mp1",
70 "ac3", 69 "ac3",
71 "3gpp", 70 "3gpp",
72 "3gp2", 71 "3gp2",
73 "amrf", 72 "amrf",
73 "amr",
74 "ima4",
75 "ima",
74 NULL 76 NULL
75 }; 77 };
76 const Sound_DecoderFunctions __Sound_DecoderFunctions_CoreAudio = 78 const Sound_DecoderFunctions __Sound_DecoderFunctions_CoreAudio =
77 { 79 {
78 { 80 {
79 extensions_coreaudio, 81 extensions_coreaudio,
80 "Decode audio through Core Audio through", 82 "Decode audio through Core Audio through",
81 "Eric Wing <ewing.public@playcontrol.net>", 83 "Eric Wing <ewing . public @ playcontrol.net>",
82 "http://playcontrol.net" 84 "http://playcontrol.net"
83 }, 85 },
84 86
85 CoreAudio_init, /* init() method */ 87 CoreAudio_init, /* init() method */
86 CoreAudio_quit, /* quit() method */ 88 CoreAudio_quit, /* quit() method */
101 static void CoreAudio_quit(void) 103 static void CoreAudio_quit(void)
102 { 104 {
103 /* it's a no-op. */ 105 /* it's a no-op. */
104 } /* CoreAudio_quit */ 106 } /* CoreAudio_quit */
105 107
106 108 /*
107 static AudioFileTypeID CoreAudio_GetAudioTypeForExtension(const char* file_extension) 109 http://developer.apple.com/library/ios/#documentation/MusicAudio/Reference/AudioFileConvertRef/Reference/reference.html
108 { 110 kAudioFileAIFFType = 'AIFF',
109 if( (__Sound_strcasecmp(file_extension, "aif") == 0)
110 || (__Sound_strcasecmp(file_extension, "aiff") == 0)
111 || (__Sound_strcasecmp(file_extension, "aifc") == 0)
112 )
113 {
114 return kAudioFileAIFCType;
115 }
116 else if( (__Sound_strcasecmp(file_extension, "wav") == 0)
117 || (__Sound_strcasecmp(file_extension, "wave") == 0)
118 )
119 {
120 return kAudioFileWAVEType;
121 }
122 else if( (__Sound_strcasecmp(file_extension, "mp3") == 0)
123 )
124 {
125 return kAudioFileMP3Type;
126 }
127 else if( (__Sound_strcasecmp(file_extension, "mp4") == 0)
128 )
129 {
130 return kAudioFileMPEG4Type;
131 }
132 else if( (__Sound_strcasecmp(file_extension, "m4a") == 0)
133 )
134 {
135 return kAudioFileM4AType;
136 }
137 else if( (__Sound_strcasecmp(file_extension, "aac") == 0)
138 )
139 {
140 return kAudioFileAAC_ADTSType;
141 }
142 else if( (__Sound_strcasecmp(file_extension, "aac") == 0)
143 )
144 {
145 return kAudioFileAAC_ADTSType;
146 }
147 else if( (__Sound_strcasecmp(file_extension, "caf") == 0)
148 || (__Sound_strcasecmp(file_extension, "caff") == 0)
149 )
150 {
151 return kAudioFileCAFType;
152 }
153 else if( (__Sound_strcasecmp(file_extension, "Sd2f") == 0)
154 )
155 {
156 return kAudioFileSoundDesigner2Type;
157 }
158 else if( (__Sound_strcasecmp(file_extension, "au") == 0)
159 || (__Sound_strcasecmp(file_extension, "next") == 0)
160 )
161 {
162 return kAudioFileNextType;
163 }
164 else if( (__Sound_strcasecmp(file_extension, "mp2") == 0)
165 )
166 {
167 return kAudioFileMP2Type;
168 }
169 else if( (__Sound_strcasecmp(file_extension, "mp1") == 0)
170 )
171 {
172 return kAudioFileMP1Type;
173 }
174 else if( (__Sound_strcasecmp(file_extension, "ac3") == 0)
175 )
176 {
177 return kAudioFileAC3Type;
178 }
179 else if( (__Sound_strcasecmp(file_extension, "3gpp") == 0)
180 )
181 {
182 return kAudioFile3GPType;
183 }
184 else if( (__Sound_strcasecmp(file_extension, "3gp2") == 0)
185 )
186 {
187 return kAudioFile3GP2Type;
188 }
189 else if( (__Sound_strcasecmp(file_extension, "amrf") == 0)
190 )
191 {
192 return kAudioFileAMRType;
193 }
194 else
195 {
196 return 0;
197 }
198 /*
199 kAudioFilhttp://developer.apple.com/library/ios/#documentation/MusicAudio/Reference/AudioFileConvertRef/Reference/reference.htmleAIFFType = 'AIFF',
200 kAudioFileAIFCType = 'AIFC', 111 kAudioFileAIFCType = 'AIFC',
201 kAudioFileWAVEType = 'WAVE', 112 kAudioFileWAVEType = 'WAVE',
202 kAudioFileSoundDesigner2Type = 'Sd2f', 113 kAudioFileSoundDesigner2Type = 'Sd2f',
203 kAudioFileNextType = 'NeXT', 114 kAudioFileNextType = 'NeXT',
204 kAudioFileMP3Type = 'MPG3', 115 kAudioFileMP3Type = 'MPG3',
210 kAudioFileM4AType = 'm4af', 121 kAudioFileM4AType = 'm4af',
211 kAudioFileCAFType = 'caff', 122 kAudioFileCAFType = 'caff',
212 kAudioFile3GPType = '3gpp', 123 kAudioFile3GPType = '3gpp',
213 kAudioFile3GP2Type = '3gp2', 124 kAudioFile3GP2Type = '3gp2',
214 kAudioFileAMRType = 'amrf' 125 kAudioFileAMRType = 'amrf'
215 126 */
216 */ 127 static AudioFileTypeID CoreAudio_GetAudioTypeForExtension(const char* file_extension)
128 {
129 if( (__Sound_strcasecmp(file_extension, "aif") == 0)
130 || (__Sound_strcasecmp(file_extension, "aiff") == 0)
131 || (__Sound_strcasecmp(file_extension, "aifc") == 0)
132 )
133 {
134 return kAudioFileAIFCType;
135 }
136 else if( (__Sound_strcasecmp(file_extension, "wav") == 0)
137 || (__Sound_strcasecmp(file_extension, "wave") == 0)
138 )
139 {
140 return kAudioFileWAVEType;
141 }
142 else if( (__Sound_strcasecmp(file_extension, "mp3") == 0)
143 )
144 {
145 return kAudioFileMP3Type;
146 }
147 else if( (__Sound_strcasecmp(file_extension, "mp4") == 0)
148 )
149 {
150 return kAudioFileMPEG4Type;
151 }
152 else if( (__Sound_strcasecmp(file_extension, "m4a") == 0)
153 )
154 {
155 return kAudioFileM4AType;
156 }
157 else if( (__Sound_strcasecmp(file_extension, "aac") == 0)
158 )
159 {
160 return kAudioFileAAC_ADTSType;
161 }
162 else if( (__Sound_strcasecmp(file_extension, "aac") == 0)
163 )
164 {
165 return kAudioFileAAC_ADTSType;
166 }
167 else if( (__Sound_strcasecmp(file_extension, "caf") == 0)
168 || (__Sound_strcasecmp(file_extension, "caff") == 0)
169 )
170 {
171 return kAudioFileCAFType;
172 }
173 else if( (__Sound_strcasecmp(file_extension, "Sd2f") == 0)
174 || (__Sound_strcasecmp(file_extension, "sd2") == 0)
175 )
176 {
177 return kAudioFileSoundDesigner2Type;
178 }
179 else if( (__Sound_strcasecmp(file_extension, "au") == 0)
180 || (__Sound_strcasecmp(file_extension, "next") == 0)
181 )
182 {
183 return kAudioFileNextType;
184 }
185 else if( (__Sound_strcasecmp(file_extension, "mp2") == 0)
186 )
187 {
188 return kAudioFileMP2Type;
189 }
190 else if( (__Sound_strcasecmp(file_extension, "mp1") == 0)
191 )
192 {
193 return kAudioFileMP1Type;
194 }
195 else if( (__Sound_strcasecmp(file_extension, "ac3") == 0)
196 )
197 {
198 return kAudioFileAC3Type;
199 }
200 else if( (__Sound_strcasecmp(file_extension, "3gpp") == 0)
201 )
202 {
203 return kAudioFile3GPType;
204 }
205 else if( (__Sound_strcasecmp(file_extension, "3gp2") == 0)
206 )
207 {
208 return kAudioFile3GP2Type;
209 }
210 else if( (__Sound_strcasecmp(file_extension, "amrf") == 0)
211 || (__Sound_strcasecmp(file_extension, "amr") == 0)
212 )
213 {
214 return kAudioFileAMRType;
215 }
216 else if( (__Sound_strcasecmp(file_extension, "ima4") == 0)
217 || (__Sound_strcasecmp(file_extension, "ima") == 0)
218 )
219 {
220 /* not sure about this one */
221 return kAudioFileCAFType;
222 }
223 else
224 {
225 return 0;
226 }
227
217 } 228 }
218 229
219 static const char* CoreAudio_FourCCToString(int32_t error_code) 230 static const char* CoreAudio_FourCCToString(int32_t error_code)
220 { 231 {
221 static char return_string[16]; 232 static char return_string[16];
327 if (error_result != noErr) 338 if (error_result != noErr)
328 { 339 {
329 AudioFileClose(*audio_file_id); 340 AudioFileClose(*audio_file_id);
330 free(audio_file_id); 341 free(audio_file_id);
331 free(core_audio_file_container); 342 free(core_audio_file_container);
332 SNDDBG(("Core Audio: AudioFileGetProperty failed. reason: [%s].\n", CoreAudio_FourCCToString(error_result))); 343 SNDDBG(("Core Audio: AudioFileGetProperty failed. reason: [%s]", CoreAudio_FourCCToString(error_result)));
333 BAIL_MACRO("Core Audio: Not valid audio data.", 0); 344 BAIL_MACRO("Core Audio: Not valid audio data.", 0);
334 } /* if */ 345 } /* if */
335 346
336 format_size = sizeof(estimated_duration); 347 format_size = sizeof(estimated_duration);
337 error_result = AudioFileGetProperty( 348 error_result = AudioFileGetProperty(
353 core_audio_file_container->audioFileID = audio_file_id; 364 core_audio_file_container->audioFileID = audio_file_id;
354 365
355 internal->decoder_private = core_audio_file_container; 366 internal->decoder_private = core_audio_file_container;
356 367
357 sample->flags = SOUND_SAMPLEFLAG_CANSEEK; 368 sample->flags = SOUND_SAMPLEFLAG_CANSEEK;
358 sample->actual.rate = (Uint32) actual_format.mSampleRate; 369 sample->actual.rate = (UInt32) actual_format.mSampleRate;
359 sample->actual.channels = (Uint8)actual_format.mChannelsPerFrame; 370 sample->actual.channels = (UInt8)actual_format.mChannelsPerFrame;
360 internal->total_time = (Sint32)(estimated_duration * 1000.0 + 0.5); 371 internal->total_time = (SInt32)(estimated_duration * 1000.0 + 0.5);
361 372
362 #if 0 373 #if 0
363 /* FIXME: Both Core Audio and SDL 1.3 support float and 32-bit formats */ 374 /* FIXME: Both Core Audio and SDL 1.3 support float and 32-bit formats */
364 if(actual_format.mFormatFlags & kAudioFormatFlagIsBigEndian) 375 if(actual_format.mFormatFlags & kAudioFormatFlagIsBigEndian)
365 { 376 {
472 output_format.mFramesPerPacket = 1; // We know for linear PCM, the definition is 1 frame per packet 483 output_format.mFramesPerPacket = 1; // We know for linear PCM, the definition is 1 frame per packet
473 484
474 if(sample->desired.format == 0) 485 if(sample->desired.format == 0)
475 { 486 {
476 // do AUDIO_S16SYS 487 // do AUDIO_S16SYS
477 output_format.mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; 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.
478 output_format.mBitsPerChannel = 16; // We know we want 16-bit 489 output_format.mBitsPerChannel = 16; // We know we want 16-bit
479 } 490 }
480 else 491 else
481 { 492 {
482 output_format.mFormatFlags = 0; // clear flags 493 output_format.mFormatFlags = 0; // clear flags
483 output_format.mFormatFlags |= kAudioFormatFlagIsPacked; // I seem to read failures problems without this 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.
484 // Mask against bitsize 495 // Mask against bitsize
485 if(0xFF & sample->desired.format) 496 if(0xFF & sample->desired.format)
486 { 497 {
487 output_format.mBitsPerChannel = 16; /* 16-bit */ 498 output_format.mBitsPerChannel = 16; /* 16-bit */
488 } 499 }
510 { 521 {
511 // no flag set for little endian 522 // no flag set for little endian
512 } 523 }
513 } 524 }
514 525
515 output_format.mBitsPerChannel = 16; // We know we want 16-bit
516 output_format.mBytesPerPacket = output_format.mBitsPerChannel/8 * output_format.mChannelsPerFrame; // e.g. 16-bits/8 * channels => so 2-bytes per channel per frame 526 output_format.mBytesPerPacket = output_format.mBitsPerChannel/8 * output_format.mChannelsPerFrame; // e.g. 16-bits/8 * channels => so 2-bytes per channel per frame
517 output_format.mBytesPerFrame = output_format.mBitsPerChannel/8 * output_format.mChannelsPerFrame; // For PCM, since 1 frame is 1 packet, it is the same as mBytesPerPacket 527 output_format.mBytesPerFrame = output_format.mBitsPerChannel/8 * output_format.mChannelsPerFrame; // For PCM, since 1 frame is 1 packet, it is the same as mBytesPerPacket
518 528
519 529
520 /* 530 /*
581 591
582 592
583 static Uint32 CoreAudio_read(Sound_Sample *sample) 593 static Uint32 CoreAudio_read(Sound_Sample *sample)
584 { 594 {
585 OSStatus error_result = noErr; 595 OSStatus error_result = noErr;
586 SInt64 buffer_size_in_frames = 0; 596 /* Documentation/example shows SInt64, but is problematic for big endian
587 SInt64 buffer_size_in_frames_remaining = 0; 597 * on 32-bit cast for ExtAudioFileRead() because it takes the upper
588 SInt64 total_frames_read = 0; 598 * bits which turn to 0.
589 Uint32 data_buffer_size = 0; 599 */
590 Uint32 bytes_remaining = 0; 600 UInt32 buffer_size_in_frames = 0;
591 Uint32 total_bytes_read = 0; 601 UInt32 buffer_size_in_frames_remaining = 0;
602 UInt32 total_frames_read = 0;
603 UInt32 data_buffer_size = 0;
604 UInt32 bytes_remaining = 0;
605 size_t total_bytes_read = 0;
592 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; 606 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
593 CoreAudioFileContainer* core_audio_file_container = (CoreAudioFileContainer *) internal->decoder_private; 607 CoreAudioFileContainer* core_audio_file_container = (CoreAudioFileContainer *) internal->decoder_private;
594 Uint32 max_buffer_size = internal->buffer_size; 608 UInt32 max_buffer_size = internal->buffer_size;
595 609
596 // printf("internal->buffer_size=%d, internal->buffer=0x%x, sample->buffer_size=%d\n", internal->buffer_size, internal->buffer, sample->buffer_size); 610 // printf("internal->buffer_size=%d, internal->buffer=0x%x, sample->buffer_size=%d\n", internal->buffer_size, internal->buffer, sample->buffer_size);
597 // printf("internal->max_buffer_size=%d\n", max_buffer_size); 611 // printf("internal->max_buffer_size=%d\n", max_buffer_size);
598 612
599 /* Compute how many frames will fit into our max buffer size */ 613 /* Compute how many frames will fit into our max buffer size */
612 626
613 627
614 bytes_remaining = max_buffer_size; 628 bytes_remaining = max_buffer_size;
615 buffer_size_in_frames_remaining = buffer_size_in_frames; 629 buffer_size_in_frames_remaining = buffer_size_in_frames;
616 630
617 // oops. Due to a bug in how I opened the file, I was misled to believe that Core Audio 631 // oops. Due to the kAudioFormatFlagIsPacked bug,
618 // was not always filling my entire requested buffer. So this while-loop might be unnecessary. 632 // I was misled to believe that Core Audio
619 // However, I have not exhaustively tested all formats, so maybe it is possible this loop is useful. 633 // was not always filling my entire requested buffer.
634 // So this while-loop might be unnecessary.
635 // However, I have not exhaustively tested all formats,
636 // so maybe it is possible this loop is useful.
637 // It might also handle the not-evenly disvisible case above.
620 while(buffer_size_in_frames_remaining > 0 && !(sample->flags & SOUND_SAMPLEFLAG_EOF)) 638 while(buffer_size_in_frames_remaining > 0 && !(sample->flags & SOUND_SAMPLEFLAG_EOF))
621 { 639 {
622 640
623 data_buffer_size = (Uint32)(buffer_size_in_frames * core_audio_file_container->outputFormat->mBytesPerFrame); 641 data_buffer_size = (UInt32)(buffer_size_in_frames * core_audio_file_container->outputFormat->mBytesPerFrame);
624 // printf("data_buffer_size=%d\n", data_buffer_size); 642 // printf("data_buffer_size=%d\n", data_buffer_size);
625 643
626 buffer_size_in_frames = buffer_size_in_frames_remaining; 644 buffer_size_in_frames = buffer_size_in_frames_remaining;
627 645
628 // printf("reading buffer_size_in_frames=%"PRId64"\n", buffer_size_in_frames); 646 // printf("reading buffer_size_in_frames=%"PRId64"\n", buffer_size_in_frames);
629 647
630 648
631 audio_buffer_list.mBuffers[0].mDataByteSize = bytes_remaining; 649 audio_buffer_list.mBuffers[0].mDataByteSize = bytes_remaining;
632 audio_buffer_list.mBuffers[0].mData = &(((Uint8*)internal->buffer)[total_bytes_read]); 650 audio_buffer_list.mBuffers[0].mData = &(((UInt8*)internal->buffer)[total_bytes_read]);
633 651
634 652
635 /* Read the data into an AudioBufferList */ 653 /* Read the data into an AudioBufferList */
636 error_result = ExtAudioFileRead(core_audio_file_container->extAudioFileRef, (UInt32*)&buffer_size_in_frames, &audio_buffer_list); 654 error_result = ExtAudioFileRead(core_audio_file_container->extAudioFileRef, &buffer_size_in_frames, &audio_buffer_list);
637 if(error_result == noErr) 655 if(error_result == noErr)
638 { 656 {
639 657
640 658
641 /* Success */ 659 /* Success */
642 660
643 total_frames_read += buffer_size_in_frames; 661 total_frames_read += buffer_size_in_frames;
644 buffer_size_in_frames_remaining = buffer_size_in_frames_remaining - buffer_size_in_frames; 662 buffer_size_in_frames_remaining = buffer_size_in_frames_remaining - buffer_size_in_frames;
645 663
646 printf("read buffer_size_in_frames=%"PRId64", buffer_size_in_frames_remaining=%"PRId64"\n", buffer_size_in_frames, buffer_size_in_frames_remaining); 664 // printf("read buffer_size_in_frames=%"PRId64", buffer_size_in_frames_remaining=%"PRId64"\n", buffer_size_in_frames, buffer_size_in_frames_remaining);
647 665
648 /* ExtAudioFileRead returns the number of frames actually read. Need to convert back to bytes. */ 666 /* ExtAudioFileRead returns the number of frames actually read. Need to convert back to bytes. */
649 data_buffer_size = (Uint32)(buffer_size_in_frames * core_audio_file_container->outputFormat->mBytesPerFrame); 667 data_buffer_size = (UInt32)(buffer_size_in_frames * core_audio_file_container->outputFormat->mBytesPerFrame);
650 // printf("data_buffer_size=%d\n", data_buffer_size); 668 // printf("data_buffer_size=%d\n", data_buffer_size);
651 669
652 total_bytes_read += data_buffer_size; 670 total_bytes_read += data_buffer_size;
653 bytes_remaining = bytes_remaining - data_buffer_size; 671 bytes_remaining = bytes_remaining - data_buffer_size;
654 672
671 689
672 if( (!(sample->flags & SOUND_SAMPLEFLAG_EOF)) && (total_bytes_read < max_buffer_size)) 690 if( (!(sample->flags & SOUND_SAMPLEFLAG_EOF)) && (total_bytes_read < max_buffer_size))
673 { 691 {
674 SNDDBG(("Core Audio: ExtAudioFileReadfailed SOUND_SAMPLEFLAG_EAGAIN, reason: [total_bytes_read < max_buffer_size], %d, %d.\n", total_bytes_read , max_buffer_size)); 692 SNDDBG(("Core Audio: ExtAudioFileReadfailed SOUND_SAMPLEFLAG_EAGAIN, reason: [total_bytes_read < max_buffer_size], %d, %d.\n", total_bytes_read , max_buffer_size));
675 693
676 // Don't know what to do here. 694 /* Don't know what to do here. */
677 sample->flags |= SOUND_SAMPLEFLAG_EAGAIN; 695 sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
678 } 696 }
679 return total_bytes_read; 697 return total_bytes_read;
680 } /* CoreAudio_read */ 698 } /* CoreAudio_read */
681 699
730 } /* CoreAudio_seek */ 748 } /* CoreAudio_seek */
731 749
732 #endif /* SOUND_SUPPORTS_COREAUDIO */ 750 #endif /* SOUND_SUPPORTS_COREAUDIO */
733 751
734 752
735 /* end of ogg.c ... */ 753 /* end of coreaudio.c ... */
736 754