📄 audio_osx_source.cc
字号:
/* -*- c++ -*- *//* * Copyright 2006 Free Software Foundation, Inc. * * This file is part of GNU Radio. * * GNU Radio is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * GNU Radio 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Radio; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */#ifdef HAVE_CONFIG_H#include "config.h"#endif#define _USE_OMNI_THREADS_#include <audio_osx_source.h>#include <gr_io_signature.h>#include <stdexcept>#include <audio_osx.h>#define _OSX_AU_DEBUG_ 0#define _OSX_DO_LISTENERS_ 0void PrintStreamDesc (AudioStreamBasicDescription *inDesc){ if (inDesc == NULL) { fprintf (stderr, "PrintStreamDesc: Can't print a NULL desc!\n"); return; } fprintf (stderr, " Sample Rate : %g\n", inDesc->mSampleRate); fprintf (stderr, " Format ID : %4s\n", (char*)&inDesc->mFormatID); fprintf (stderr, " Format Flags : %lX\n", inDesc->mFormatFlags); fprintf (stderr, " Bytes per Packet : %ld\n", inDesc->mBytesPerPacket); fprintf (stderr, " Frames per Packet : %ld\n", inDesc->mFramesPerPacket); fprintf (stderr, " Bytes per Frame : %ld\n", inDesc->mBytesPerFrame); fprintf (stderr, " Channels per Frame : %ld\n", inDesc->mChannelsPerFrame); fprintf (stderr, " Bits per Channel : %ld\n", inDesc->mBitsPerChannel);}// FIXME these should query some kind of user preferenceaudio_osx_source::audio_osx_source (int sample_rate, const std::string device_name, bool do_block, int channel_config, int max_sample_count) : gr_sync_block ("audio_osx_source", gr_make_io_signature (0, 0, 0), gr_make_io_signature (0, 0, 0)), d_deviceSampleRate (0.0), d_outputSampleRate (0.0), d_channel_config (0), d_inputBufferSizeFrames (0), d_inputBufferSizeBytes (0), d_outputBufferSizeFrames (0), d_outputBufferSizeBytes (0), d_deviceBufferSizeFrames (0), d_deviceBufferSizeBytes (0), d_leadSizeFrames (0), d_leadSizeBytes (0), d_trailSizeFrames (0), d_trailSizeBytes (0), d_extraBufferSizeFrames (0), d_extraBufferSizeBytes (0), d_queueSampleCount (0), d_max_sample_count (0), d_n_AvailableInputFrames (0), d_n_ActualInputFrames (0), d_n_user_channels (0), d_n_max_channels (0), d_n_deviceChannels (0), d_do_block (do_block), d_passThrough (false), d_internal (0), d_cond_data (0), d_buffers (0), d_InputAU (0), d_InputBuffer (0), d_OutputBuffer (0), d_AudioConverter (0){ if (sample_rate <= 0) { fprintf (stderr, "Invalid Sample Rate: %d\n", sample_rate); throw std::invalid_argument ("audio_osx_source::audio_osx_source"); } else d_outputSampleRate = (Float64) sample_rate; if (channel_config <= 0 & channel_config != -1) { fprintf (stderr, "Invalid Channel Config: %d\n", channel_config); throw std::invalid_argument ("audio_osx_source::audio_osx_source"); } else if (channel_config == -1) {// no user input; try "device name" instead int l_n_channels = (int) strtol (device_name.data(), (char **)NULL, 10); if (l_n_channels == 0 & errno) { fprintf (stderr, "Error Converting Device Name: %d\n", errno); throw std::invalid_argument ("audio_osx_source::audio_osx_source"); } if (l_n_channels <= 0) channel_config = 2; else channel_config = l_n_channels; } d_channel_config = channel_config;// check that the max # of samples to store is valid if (max_sample_count == -1) max_sample_count = sample_rate; else if (max_sample_count <= 0) { fprintf (stderr, "Invalid Max Sample Count: %d\n", max_sample_count); throw std::invalid_argument ("audio_osx_source::audio_osx_source"); } d_max_sample_count = max_sample_count;#if _OSX_AU_DEBUG_ fprintf (stderr, "source(): max # samples = %ld\n", d_max_sample_count);#endif OSStatus err = noErr;// create the default AudioUnit for input// Open the default input unit ComponentDescription InputDesc; InputDesc.componentType = kAudioUnitType_Output; InputDesc.componentSubType = kAudioUnitSubType_HALOutput; InputDesc.componentManufacturer = kAudioUnitManufacturer_Apple; InputDesc.componentFlags = 0; InputDesc.componentFlagsMask = 0; Component comp = FindNextComponent (NULL, &InputDesc); if (comp == NULL) { fprintf (stderr, "FindNextComponent Error\n"); throw std::runtime_error ("audio_osx_source::audio_osx_source"); } err = OpenAComponent (comp, &d_InputAU); CheckErrorAndThrow (err, "OpenAComponent", "audio_osx_source::audio_osx_source"); UInt32 enableIO;// must enable the AUHAL for input and disable output // before setting the AUHAL's current device// Enable input on the AUHAL enableIO = 1; err = AudioUnitSetProperty (d_InputAU, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, // input element &enableIO, sizeof (UInt32)); CheckErrorAndThrow (err, "AudioUnitSetProperty Input Enable", "audio_osx_source::audio_osx_source");// Disable output on the AUHAL enableIO = 0; err = AudioUnitSetProperty (d_InputAU, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, // output element &enableIO, sizeof (UInt32)); CheckErrorAndThrow (err, "AudioUnitSetProperty Output Disable", "audio_osx_source::audio_osx_source");// set the default input device for our input AU SetDefaultInputDeviceAsCurrent ();#if _OSX_DO_LISTENERS_// set up a listener if default hardware input device changes err = AudioHardwareAddPropertyListener (kAudioHardwarePropertyDefaultInputDevice, (AudioHardwarePropertyListenerProc) HardwareListener, this); CheckErrorAndThrow (err, "AudioHardwareAddPropertyListener", "audio_osx_source::audio_osx_source");// Add a listener for any changes in the input AU's output stream// the function "UnitListener" will be called if the stream format// changes for whatever reason err = AudioUnitAddPropertyListener (d_InputAU, kAudioUnitProperty_StreamFormat, (AudioUnitPropertyListenerProc) UnitListener, this); CheckErrorAndThrow (err, "Adding Unit Property Listener", "audio_osx_source::audio_osx_source");#endif// Now find out if it actually can do input. UInt32 hasInput = 0; UInt32 dataSize = sizeof (hasInput); err = AudioUnitGetProperty (d_InputAU, kAudioOutputUnitProperty_HasIO, kAudioUnitScope_Input, 1, &hasInput, &dataSize); CheckErrorAndThrow (err, "AudioUnitGetProperty HasIO", "audio_osx_source::audio_osx_source"); if (hasInput == 0) { fprintf (stderr, "Selected Audio Device does not support Input.\n"); throw std::runtime_error ("audio_osx_source::audio_osx_source"); }// Set up a callback function to retrieve input from the Audio Device AURenderCallbackStruct AUCallBack; AUCallBack.inputProc = (AURenderCallback)(audio_osx_source::AUInputCallback); AUCallBack.inputProcRefCon = this; err = AudioUnitSetProperty (d_InputAU, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &AUCallBack, sizeof (AURenderCallbackStruct)); CheckErrorAndThrow (err, "AudioUnitSetProperty Input Callback", "audio_osx_source::audio_osx_source"); UInt32 propertySize; AudioStreamBasicDescription asbd_device, asbd_client, asbd_user;// asbd_device: ASBD of the device that is creating the input data stream// asbd_client: ASBD of the client size (output) of the hardware device// asbd_user: ASBD of the user's arguments// Get the Stream Format (device side) propertySize = sizeof (asbd_device); err = AudioUnitGetProperty (d_InputAU, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &asbd_device, &propertySize); CheckErrorAndThrow (err, "AudioUnitGetProperty Device Input Stream Format", "audio_osx_source::audio_osx_source");#if _OSX_AU_DEBUG_ fprintf (stderr, "\n---- Device Stream Format ----\n" ); PrintStreamDesc (&asbd_device);#endif// Get the Stream Format (client side) propertySize = sizeof (asbd_client); err = AudioUnitGetProperty (d_InputAU, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &asbd_client, &propertySize); CheckErrorAndThrow (err, "AudioUnitGetProperty Device Ouput Stream Format", "audio_osx_source::audio_osx_source");#if _OSX_AU_DEBUG_ fprintf (stderr, "\n---- Client Stream Format ----\n"); PrintStreamDesc (&asbd_client);#endif// Set the format of all the AUs to the input/output devices channel count// get the max number of input (& thus output) channels supported by// this device d_n_max_channels = asbd_client.mChannelsPerFrame;// create the output io signature;// no input siganture to set (source is hardware) set_output_signature (gr_make_io_signature (1, d_n_max_channels, sizeof (float)));// allocate the output circular buffer(s), one per channel d_buffers = (circular_buffer<float>**) new circular_buffer<float>* [d_n_max_channels]; UInt32 n_alloc = (UInt32) ceil ((double) d_max_sample_count); for (UInt32 n = 0; n < d_n_max_channels; n++) { d_buffers[n] = new circular_buffer<float> (n_alloc, false, false); } d_deviceSampleRate = asbd_device.mSampleRate; d_n_deviceChannels = asbd_device.mChannelsPerFrame;// create an ASBD for the user's wants asbd_user.mSampleRate = d_outputSampleRate; asbd_user.mFormatID = kAudioFormatLinearPCM; asbd_user.mFormatFlags = (kLinearPCMFormatFlagIsFloat | GR_PCM_ENDIANNESS | kLinearPCMFormatFlagIsPacked | kAudioFormatFlagIsNonInterleaved); asbd_user.mBytesPerPacket = 4; asbd_user.mFramesPerPacket = 1; asbd_user.mBytesPerFrame = 4; asbd_user.mChannelsPerFrame = d_n_max_channels; asbd_user.mBitsPerChannel = 32; if (d_deviceSampleRate == d_outputSampleRate) {// no need to do conversion if asbd_client matches user wants d_passThrough = true; d_leadSizeFrames = d_trailSizeFrames = 0L; } else { d_passThrough = false;// Create the audio converter err = AudioConverterNew (&asbd_client, &asbd_user, &d_AudioConverter); CheckErrorAndThrow (err, "AudioConverterNew", "audio_osx_source::audio_osx_source");// Set the audio converter sample rate quality to "max" ...// requires more samples, but should sound nicer UInt32 ACQuality = kAudioConverterQuality_Max; propertySize = sizeof (ACQuality); err = AudioConverterSetProperty (d_AudioConverter, kAudioConverterSampleRateConverterQuality, propertySize, &ACQuality); CheckErrorAndThrow (err, "AudioConverterSetProperty " "SampleRateConverterQuality", "audio_osx_source::audio_osx_source");// set the audio converter's prime method to "pre",// which uses both leading and trailing frames// from the "current input". All of this is handled// internally by the AudioConverter; we just supply// the frames for conversion.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -