translation:adc:audio:technical_qa:qa1394_using_nssound_with_coreaudio_on_mac_os_10.3.x

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

回答: アプリケーションによっては、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 <Cocoa/Cocoa.h>
#import <CoreAudio/CoreAudio.h>
 
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 <Cocoa/Cocoa.h>
#import <CoreAudio/CoreAudio.h>
 
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-30NSString使用時のAudioDeviceAddIOProc使用によるCore Audio IOProcの入力バッファがNULLになる問題の対処に関する新規ドキュメント
  • translation/adc/audio/technical_qa/qa1394_using_nssound_with_coreaudio_on_mac_os_10.3.x.txt
  • 最終更新: 2015-01-06 11:51
  • (外部編集)