====== QA1394: Mac OS X v10.3.xでCoreAudioと共にNSSoundを使う ======
原文 //Technical Q&A QA1394: Using NSSound with CoreAudio on Mac OS 10.3.x [[http://developer.apple.com/qa/qa2005/qa1394.html]] //
===== Mac OS X v10.3.xでCoreAudioと共にNSSoundを使う場合、なぜIOProcコールバックで得られるデータがNULLになるのでしょうか? =====
回答: アプリケーションによっては、Application Kitフレームワークの''NSSound''とCore Audioを同一アプリケーション内で一緒に使った方が便利なことがあります。
開発者は''NSSound''がCore AudioのHAL(ハードウェア抽象化層)のIOProcとやり取りしている可能性を考慮しなければなりません。
MacOS 10.3.xシステムでは、Core AudioフレームワークのIOProcコールバックと同じプロセスの中で''NSSound''クラスを使うと、IOProcコールバックの入力バッファがNULLになる可能性があります。
このバグは、''NSSound''が音声出力に使う装置、つまりデフォルト音声出力装置にCore AudioのIOProcを追加するアプリケーションに影響を及ぼします。
Core AudioのIOProcを音声装置に追加する前に''NSSound''を呼ぶと、アプリケーションはIOProc内でNULL入力バッファを受け取る事になるでしょう。
この問題を回避するには、あらゆる''NSSound''呼び出しの前に''AudioDeviceAddIOProc''を呼ぶ必要があります。
**Listing 1:** 問題有りのサンプル
#import
#import
OSStatus recordIOProc ( AudioDeviceID inDevice,
const AudioTimeStamp* inNow,
const AudioBufferList* inInputData,
const AudioTimeStamp* inInputTime,
AudioBufferList* outOutputData,
const AudioTimeStamp* inOutputTime,
void* inClientData )
{
if ( inInputData )
{
if ( inInputData->mBuffers[0].mData == NULL )
NSLog (@"CoreAudio IOProcの入力バッファはNULL");
}
return noErr;
}
int main()
{
NSAutoreleasePool * pool = [NSAutoreleasePool new];
AudioDeviceID device;
UInt32 theSize = sizeof(AudioDeviceID);
verify_noerr( AudioHardwareGetProperty ( kAudioHardwarePropertyDefaultInputDevice, &theSize, & device ) );
NSSound *sound = [[NSSound alloc] initWithContentsOfFile:
@"/System/Library/Sounds/Submarine.aiff" byReference:NO];
[sound play];
verify_noerr( AudioDeviceAddIOProc ( device, recordIOProc, NULL ) );
verify_noerr( AudioDeviceStart ( device, recordIOProc ) );
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]];
verify_noerr( AudioDeviceStop ( device, recordIOProc ) );
verify_noerr( AudioDeviceRemoveIOProc ( device, recordIOProc ) );
[sound release];
[pool release];
return 0;
}
上のサンプルコードを実行すると、標準出力(stdout)に何回も"CoreAudio IOProcの入力バッファはNULL"と表示される事がわかります。
この問題を回避するには、NSSound
呼び出しの前に、AudioDeviceAddIOProc
を呼び出します。
上記サンプルの問題修正版を以下に掲載します:
**Listing 2:** 問題を修正したサンプル
#import
#import
OSStatus recordIOProc ( AudioDeviceID inDevice,
const AudioTimeStamp* inNow,
const AudioBufferList* inInputData,
const AudioTimeStamp* inInputTime,
AudioBufferList* outOutputData,
const AudioTimeStamp* inOutputTime,
void* inClientData )
{
if ( inInputData )
{
if ( inInputData->mBuffers[0].mData == NULL )
NSLog (@"CoreAudio IOProcの入力バッファはNULL");
}
return noErr;
}
int main()
{
NSAutoreleasePool * pool = [NSAutoreleasePool new];
AudioDeviceID device;
UInt32 theSize = sizeof(AudioDeviceID);
verify_noerr( AudioHardwareGetProperty ( kAudioHardwarePropertyDefaultInputDevice, &theSize, & device ) );
// NSSoundを使う「前」に呼ぶ
verify_noerr( AudioDeviceAddIOProc ( device, recordIOProc, NULL ) );
NSSound *sound = [[NSSound alloc] initWithContentsOfFile:
@"/System/Library/Sounds/Submarine.aiff" byReference:NO];
[sound play];
verify_noerr( AudioDeviceStart ( device, recordIOProc ) );
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]];
verify_noerr( AudioDeviceStop ( device, recordIOProc ) );
verify_noerr( AudioDeviceRemoveIOProc ( device, recordIOProc ) );
[sound release];
[pool release];
return 0;
}
ここでの変更は、AudioDeviceAddIOProc
呼び出しをNSSound
呼び出しの前に移動しただけだという点に注目して下さい。
このサンプルコードを実行しても、recordIOProcが"CoreAudio IOProcの入力バッファはNULL"と表示することはありません。つまりこれは、正しい入力バッファを受け取っている事を示しています。
''NSSound''呼び出し前に''AudioDeviceStart''を呼ぶ必要は無い事に注意してください。
''AudioDeviceAddIOProc''だけでいいのです。
===== 更新履歴 =====
^日付^内容|
|2005-06-30|NSString使用時のAudioDeviceAddIOProc使用によるCore Audio IOProcの入力バッファがNULLになる問題の対処に関する新規ドキュメント|