📄 audioinput.cpp
字号:
rollLeft = 0; rollRight = 0; num = 0; due -= from; } } } } samples = outposn; samplesDue = due; rollingLeft = rollLeft; rollingRight = rollRight; numInRolling = num; // Done return samples;}// Private storage for the "AudioInput" class.class AudioInputPrivate{public: AudioInputPrivate( unsigned int freq, unsigned int chan ) { fd = -1; notifier = 0; devFrequency = frequency = freq; devChannels = channels = chan; format = AFMT_S16_LE; devBufferSize = bufferSize = 1024; position = 0; handler = 0; } ~AudioInputPrivate() { close(); if ( handler ) delete handler; }#ifndef Q_OS_WIN32 void open( AudioInput *input, bool trialOpen = false ); void close();#endifpublic: int fd; QSocketNotifier *notifier; unsigned int devChannels; unsigned int devFrequency; unsigned int devBufferSize; unsigned int channels; unsigned int frequency; unsigned int format; unsigned int bufferSize; long position; AudioFormatHandler *handler;};#ifndef Q_OS_WIN32// The list of audio formats that we understand, in the order// in which we probe for them. We prefer formats that require// very little modification by "AudioFormatHandler" instances.static int const formatList[] = { AFMT_S16_NE, // Try 16-bit native host order first. AFMT_S16_LE, AFMT_S16_BE, AFMT_U16_LE, AFMT_U16_BE, AFMT_U8, AFMT_S8,};const int formatListSize = sizeof( formatList ) / sizeof( int );void AudioInputPrivate::open( AudioInput *input, bool trialOpen ){ // Attempt to open the DSP audio device. Try both /dev/dsp and // /dev/dsp1, because different machines have the audio input // stream on different device nodes. if ( ( fd = ::open( "/dev/dsp", O_RDONLY | O_NONBLOCK ) ) < 0 ) { if ( ( fd = ::open( "/dev/dsp1", O_RDONLY | O_NONBLOCK ) ) < 0 ) { qDebug( "error opening audio device /dev/dsp for input: %s", strerror( errno ) ); return; } } // Stop the file descriptor from being inherited across an exec().#ifdef F_SETFD fcntl( fd, F_SETFD, 1 );#endif // Search for a supported audio format. int formats = 0; if ( ioctl( fd, SNDCTL_DSP_GETFMTS, &formats ) == -1 ) { // If we can't get the supported formats, then we probably can't record. ::close( fd ); fd = -1; return; } int posn; for ( posn = 0; posn < formatListSize; ++posn ) { if ( (formats & formatList[posn]) != 0 ) { format = formatList[posn]; break; } } // Configure the device with the recommended values, // and read back what the device is really capable of. int value = (int)format; ioctl( fd, SNDCTL_DSP_SETFMT, &value ); format = (unsigned int)value; value = (int)channels; ioctl( fd, SNDCTL_DSP_CHANNELS, &value ); devChannels = (unsigned int)value;#ifdef QT_QWS_SL5XXX // The Sharp Zaurus audio input device has a bug that causes it // to halve the specified frequency when set to stereo, so we // have to double the value before setting. if ( channels == 2 ) { value = (int)(frequency * 2); ioctl( fd, SNDCTL_DSP_SPEED, &value ); devFrequency = frequency; } else { value = (int)frequency; ioctl( fd, SNDCTL_DSP_SPEED, &value ); devFrequency = (unsigned int)value; }#else value = (int)frequency; ioctl( fd, SNDCTL_DSP_SPEED, &value ); devFrequency = (unsigned int)value;#endif // Resample the input signal if it differs by more than 50 Hz // from the requested frequency rate. int diff = (int)(devFrequency - frequency); bool resample = (diff < -50 || diff > 50); if ( !resample ) frequency = devFrequency; // Create the format handler if requested. if ( !trialOpen ) { if ( handler ) delete handler; handler = AudioFormatHandler::create( format ); } // Get the recommended buffer size from the device, in 16-bit units. devBufferSize = 16; ioctl( fd, SNDCTL_DSP_GETBLKSIZE, &devBufferSize ); if ( devBufferSize < 16 ) devBufferSize = 16; if ( format != AFMT_U8 && format != AFMT_S8 ) devBufferSize /= 2; // Get the inferred buffer size for the requested frequency and channels. if ( resample || channels != devChannels ) { int devSamples = (devBufferSize / devChannels); int actualSamples = (devSamples * frequency / devFrequency) + 1; bufferSize = actualSamples * channels; if ( bufferSize < devBufferSize ) bufferSize = devBufferSize; } else { bufferSize = devBufferSize; } // Add extra audio format handlers to do channel conversion and resampling. if ( !trialOpen ) { // Convert the number of channels to the requested value. if ( channels == 2 && devChannels == 1 ) handler = new MToSAudioFormatHandler( handler ); else if ( channels == 1 && devChannels == 2 ) handler = new SToMAudioFormatHandler( handler ); // Resample the frequency rate if necessary. if ( resample && frequency != devFrequency ) { handler = new ResampleAudioFormatHandler ( handler, devFrequency, frequency, channels, bufferSize ); } } // Register a socket notifier to be appraised of data arrival. if ( !trialOpen ) { notifier = new QSocketNotifier( fd, QSocketNotifier::Read ); QObject::connect( notifier, SIGNAL(activated(int)), input, SIGNAL(dataAvailable()) ); }}void AudioInputPrivate::close(){ if ( notifier ) { delete notifier; notifier = 0; } if ( fd != -1) { ::close( fd ); fd = -1; }}#endif/*! \class AudioInput audioinput.h \brief Retrieve audio data from an input device such as a microphone.*//*! Constructs a new audio input device instance. The \a frequency and \a channels values are the recommended configuration parameters for the device. If the device is not capable of supporting the recommended values, it will choose the closest configuration that it does support.*/AudioInput::AudioInput( unsigned int frequency, unsigned int channels ){ d = new AudioInputPrivate( frequency, channels );#ifndef Q_OS_WIN32 // Do a trial open on the device, which will adjust the sample // frequency, channel count, and format to something that the // audio device actually supports. d->open( this, true ); d->close();#endif}/*! Destructs the audio input device instance.*/AudioInput::~AudioInput(){ delete d;}/*! Read a block of raw audio samples from the input device. The samples are guaranteed to be signed, 16 bits in size, and in host byte order. Returns the number of raw samples read, or zero if none are currently available. This function will not block. If the device is mono, then the number of raw samples is the same as the number of logical samples. If the device is stereo, then the number of raw samples is twice the number of logical samples. The \a length value is the maximum buffer size in raw samples. \sa frequency(), dataAvailable()*/int AudioInput::read( short *buffer, unsigned int length ){#ifdef Q_OS_WIN32 return 0;#else // Bail out if the device is not currently open. if ( d->fd == -1 ) { return 0; } // Read bytes from the device using its own encoding. if ( length > d->devBufferSize ) { length = d->devBufferSize; } unsigned int len = d->handler->readSize( length ); int result = ::read( d->fd, (char *)buffer, len ); if ( result <= 0 ) { return 0; } // Convert the device's encoding into normalized sample values. result = d->handler->convert( buffer, result ); d->position += (result / d->channels); return result;#endif}/*! Returns the number of audio channels on the input device (1 or 2).*/unsigned int AudioInput::channels() const{ return d->channels;}/*! Returns the sample rate frequency of the input device. The device returns this many logical samples per second. \sa read*/unsigned int AudioInput::frequency() const{ return d->frequency;}/*! Returns the recommended buffer size, in 16-bit units.*/unsigned int AudioInput::bufferSize() const{ return d->bufferSize;}/*! Returns TRUE if the audio input device is currently open and actively recording.*/bool AudioInput::isActive() const{#ifdef Q_OS_WIN32 return false;#else return ( d->fd != -1 );#endif}/*! Get the volume information for the microphone input. \sa setVolume()*/void AudioInput::getVolume( unsigned int& left, unsigned int& right ){#ifndef Q_OS_WIN32 unsigned int volume; int mixerHandle = open( "/dev/mixer", O_RDWR ); if ( mixerHandle >= 0 ) { ioctl( mixerHandle, MIXER_READ(AUDIO_RECORD_SOURCE), &volume ); close( mixerHandle ); } else qDebug( "get volume of audio input device failed" ); left = ((volume & 0x00FF) << 16) / 101; right = ((volume & 0xFF00) << 8) / 101;#endif}/*! Set the volume information for the microphone input. The \a left and \a right values must be between 0 and 0xFFFF, inclusive. \sa getVolume()*/void AudioInput::setVolume( unsigned int left, unsigned int right ){#ifndef Q_OS_WIN32 left = ( (int) left < 0 ) ? 0 : (( left > 0xFFFF ) ? 0xFFFF : left ); right = ( (int)right < 0 ) ? 0 : (( right > 0xFFFF ) ? 0xFFFF : right ); unsigned int rV = (right * 101) >> 16; unsigned int lV = (left * 101) >> 16; unsigned int volume = ((rV << 8) & 0xFF00) | (lV & 0x00FF); int mixerHandle = 0; if ( ( mixerHandle = open( "/dev/mixer", O_RDWR ) ) >= 0 ) { ioctl( mixerHandle, MIXER_WRITE(AUDIO_RECORD_SOURCE), &volume ); close( mixerHandle ); } else qDebug( "set volume of audio input device failed" );#endif}/*! Return the current position in logical samples since audio input was \link start() started \endlink. If the device is not currently recording, this will return the number of logical samples that were read during the last recording session. \sa read(), start()*/long AudioInput::position() const{ return d->position;}/*! Start recording audio input from the primary input device (normally a microphone). The call will be ignored if recording is already in progress. \sa stop(), position(), read()*/void AudioInput::start(){#ifndef Q_OS_WIN32 if ( d->fd == -1 ) { d->position = 0; d->open( this ); }#endif}/*! Stop recording audio input from the primary input device. The call will be ignored if recording is not currently in progress. \sa start()*/void AudioInput::stop(){#ifndef Q_OS_WIN32 d->close();#endif}/*! \fn void AudioInput::dataAvailable() This signal is emitted when new data becomes available on the audio input device. The application should \link read() read \endlink the data as soon as possible, to prevent backlogs. \sa read()*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -