⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 maccoreaudio.cxx

📁 sloedgy open sip stack source code
💻 CXX
📖 第 1 页 / 共 4 页
字号:
	bufferSizeBytes += bufferSizeBytes / 10; // +10%

   //calculate size of ABL given the last field, assum non-interleaved 
	UInt32 mChannelsPerFrame = hwASBD.mChannelsPerFrame;
	UInt32 propsize = (UInt32) &(((AudioBufferList *)0)->mBuffers[mChannelsPerFrame]);

   //malloc buffer lists
   mInputBufferList = (AudioBufferList *)malloc(propsize);
   mInputBufferList->mNumberBuffers = hwASBD.mChannelsPerFrame;

   //pre-malloc buffers for AudioBufferLists
   for(UInt32 i =0; i< mInputBufferList->mNumberBuffers ; i++) {
      mInputBufferList->mBuffers[i].mNumberChannels = 1;
      mInputBufferList->mBuffers[i].mDataByteSize = bufferSizeBytes;
      mInputBufferList->mBuffers[i].mData = malloc(bufferSizeBytes);
   }
   mRecordInputBufferSize = bufferSizeBytes;

   /** allocate ringbuffer to cache data before passing them to the converter */
   // take only one buffer -> mono, use double buffering
   mInputCircularBuffer = new CircularBuffer(bufferSizeBytes * 2);


   /** 
    * Build buffer list that is passed to the Converter to be filled with 
    * the converted frames.
    */
   // given the number of input bytes how many bytes to expect at the output?
   bufferSizeBytes += MIN_INPUT_FILL * hwASBD.mBytesPerFrame;
   propertySize = sizeof(UInt32);
   err = AudioConverterGetProperty(converter,
         kAudioConverterPropertyCalculateOutputBufferSize,
         &propertySize,
         &bufferSizeBytes);
   checkStatus(err);


   //calculate number of buffers from channels
   mChannelsPerFrame = pwlibASBD.mChannelsPerFrame;
   propsize = (UInt32) &(((AudioBufferList *)0)->mBuffers[mChannelsPerFrame]);

   //malloc buffer lists
   mOutputBufferList = (AudioBufferList *)malloc(propsize);
   mOutputBufferList->mNumberBuffers = pwlibASBD.mChannelsPerFrame;

   //pre-malloc buffers for AudioBufferLists
   for(UInt32 i =0; i< mOutputBufferList->mNumberBuffers ; i++) {
      mOutputBufferList->mBuffers[i].mNumberChannels = 1;
      mOutputBufferList->mBuffers[i].mDataByteSize = bufferSizeBytes;
      mOutputBufferList->mBuffers[i].mData = malloc(bufferSizeBytes);
   }
   mRecordOutputBufferSize = bufferSizeBytes;

   return err;
}
 

BOOL PSoundChannelCoreAudio::GetBuffers(PINDEX & size,
                  PINDEX & count)
{
   size = bufferSizeBytes;
   count = bufferCount;
   return TRUE;
}


OSStatus PSoundChannelCoreAudio::VolumeChangePropertyListener(AudioDeviceID id, 
						UInt32 chan, Boolean isInput, AudioDevicePropertyID propID, 
						void *user_data)
{
	PSoundChannelCoreAudio *This = 
						static_cast<PSoundChannelCoreAudio*>(user_data);
   OSStatus err = noErr;
   UInt32 theSize = sizeof(Float32);
   Float32 volume;

	/*
	 * Function similar to GetVolume, but we are free to ask the volume 	
	 * for the intput/output direction 
	 */

	// not all devices have a master channel
	err = AudioDeviceGetProperty(This->mDeviceID, 0, isInput,
						  kAudioDevicePropertyVolumeScalar,
						  &theSize, &volume);
	if(err != kAudioHardwareNoError) {
		// take the value of first channel to be the volume
	   theSize = sizeof(volume);
		err = AudioDeviceGetProperty(This->mDeviceID, 1, isInput,
					kAudioDevicePropertyVolumeScalar,
					&theSize, &volume);
	}

	std::cout << (isInput?"Recorder":"Player")
		  << " volume updated " << unsigned(100*volume) << std::endl;

	return noErr;
}

#include "maccoreaudio/mute_hack.inl"

/**
 * Also check out this to see the difference between streams and channels.
 * http://lists.apple.com/archives/coreaudio-api/2001/Nov/msg00155.html
 * In short a stream contains several channels, e. g. 2 in case of stereo.
 */
BOOL PSoundChannelCoreAudio::GetVolume(unsigned & volume)
{
   OSStatus err = noErr;
   UInt32 theSize;
   Float32 theValue;
   bool isInput = (direction == Player ? false : true);

   if(mDeviceID == kAudioDeviceDummy){
	   //in the case of a dummy device, we simply return 0 in all cases
      PTRACE(1, "Dummy device");
	  volume = 0;
      return TRUE;
   }


	theSize = sizeof(theValue);
	// not all devices have a master channel
	err = AudioDeviceGetProperty(mDeviceID, 0, isInput,
						  kAudioDevicePropertyVolumeScalar,
						  &theSize, &theValue);
	if(err != kAudioHardwareNoError) {
		// take the value of first channel to be the volume
	   theSize = sizeof(theValue);
		err = AudioDeviceGetProperty(mDeviceID, 1, isInput,
					kAudioDevicePropertyVolumeScalar,
					&theSize, &theValue);
	}
		

   if (err == kAudioHardwareNoError) {
     // volume is between 0 and 100? 
     volume = (unsigned) (theValue * 100);
     return TRUE;
   } else {
		volume = 0;
      return FALSE;
	}
}



/**
 * We assume that we are taking always the first stream and that it is stereo,
 * which means it maps to the first two channels of the device.
 * The Master Channel (0) is unusable because not all devices support it 
 */
BOOL PSoundChannelCoreAudio::SetVolume(unsigned volume)
{
   OSStatus err = noErr;
   Boolean isWritable;
   bool isInput = (direction == Player ? false : true);
	bool useMaster = false;


   if(mDeviceID == kAudioDeviceDummy) {
      PTRACE(1, "Dummy device");
      return FALSE;
   }

   if(state < setformat_){ // we need to know the stream format
		PTRACE(2, __func__ << "AudioStreamBasicDescription not initialized yet");
		return FALSE;
	}


	 // not all devices have a master channel 
	err = AudioDeviceGetPropertyInfo(mDeviceID, 0, isInput,
	             kAudioDevicePropertyVolumeScalar,
	             NULL, &isWritable);
	if(err != kAudioHardwareNoError) 
	{
		// check if we can access the individual channels 
		err = AudioDeviceGetPropertyInfo(mDeviceID, 1, isInput,
					kAudioDevicePropertyVolumeScalar,
					NULL, &isWritable);
					useMaster = false;
	}
	checkStatus(err);
	                                                                                             
   if ((err == kAudioHardwareNoError) && isWritable) 
	{
      // is the volume between 0 and 100 ? 
      float theValue = ((float)volume)/100.0;
		if(useMaster){
			err = AudioDeviceSetProperty(mDeviceID, NULL, 0, isInput,
						 kAudioDevicePropertyVolumeScalar,
						 sizeof(float), &theValue);
			checkStatus(err);
		} else {
			// iterate over all channels
			for(unsigned ch = 1; ch <= hwASBD.mChannelsPerFrame; ch++)
			{
				err = AudioDeviceSetProperty(mDeviceID, NULL, ch, isInput,
							 kAudioDevicePropertyVolumeScalar,
							 sizeof(float), &theValue);
				checkStatus(err);
			}
		}

		/** Not all devices can be muted, so it's no solution and wo drop the
		 * code alltogether
		{
			UInt32 mute = (volume == 0)? 1 * mute * : 0 * unmute * ;
			err = AudioDeviceSetProperty(mDeviceID, NULL, useMaster?0:1, 
					isInput, kAudioDevicePropertyMute, sizeof(UInt32), &mute);
			checkStatus(err);
			err = AudioDeviceSetProperty(mDeviceID, NULL, useMaster?0:1,
					isInput, kAudioDevicePropertySubMute, sizeof(UInt32), &mute);
			checkStatus(err);

		}
		*/

   }

	// if necessary we mute device on the pwlib level by discarding frames.
	// this works even when the device does not support muting,
	// but we have to make sure that 'this' is either a singleton instance
	// or that all threads/instances get the message to be quiet 
	{
		pthread_mutex_lock(&GetIsMuteMutex());
		isMute() = (volume == 0) ? TRUE : FALSE;
		pthread_mutex_unlock(&GetIsMuteMutex());

		/* No sense to mute this channel, it might opened just as a mixer.
		 * The playing/recording channel might be another instance of this
		 * class !!! */
	}

   if (!err)
      return TRUE;
   else
      return FALSE;
}
 

BOOL PSoundChannelCoreAudio::Write(const void *buf,PINDEX len)
{
   PTRACE(5, "Write called with len " << len);

   if(state < setbuffer_){
      PTRACE(1, __func__ << " Please initialize device first");
      return FALSE;
   }

	pthread_mutex_lock(&GetIsMuteMutex());
	if(isMute() && state != mute_){
		PTRACE(3, __func__ << "muting the " << direction << " device");
		state = mute_;
		OSStatus err = AudioOutputUnitStop(mAudioUnit); 
		checkStatus(err);
		/* isMute() => state==mute */   
	}
		
   if (mDeviceID == kAudioDeviceDummy || isMute() && state == mute_ ) {
      lastWriteCount =  len; 
  
      // safe to assume non-interleaved or mono
      UInt32 nr_samples = len / pwlibASBD.mBytesPerFrame; 
      usleep(UInt32(nr_samples/pwlibASBD.mSampleRate * 1000000)); // 10E-6 [s]
		pthread_mutex_unlock(&GetIsMuteMutex());
      return TRUE;  
   }

   // Start the device before putting datA into the buffer
   // Otherwise the thread could be locked in case the buffer is full
	// and the device is not running and draining the buffer
   if(state == setbuffer_ || (state == mute_ && !isMute())){
      state = running_;
      PTRACE(2, "Starting " << direction << " device.");
		OSStatus err = AudioOutputUnitStart(mAudioUnit);
		checkStatus(err);
   } 
	pthread_mutex_unlock(&GetIsMuteMutex());

   // Write to circular buffer with locking 
   lastWriteCount = mCircularBuffer->Fill((const char*)buf, len, true);

   return (TRUE);
}


BOOL PSoundChannelCoreAudio::PlaySound(const PSound & sound,
                  BOOL wait)
{
   if (!Write((const BYTE *)sound, sound.GetSize()))
     return FALSE;
  
   if (wait)
     return WaitForPlayCompletion();

   return TRUE;
}

BOOL PSoundChannelCoreAudio::PlayFile(const PFilePath & file,
                 BOOL wait)
{
   PTRACE(1, __func__ );
  PAssert(0, PUnimplementedFunction);

  return TRUE; 
}

BOOL PSoundChannelCoreAudio::HasPlayCompleted()
{
   PTRACE(1, __func__ );
  PAssert(0, PUnimplementedFunction);
   return false;
}

BOOL PSoundChannelCoreAudio::WaitForPlayCompletion()
{
   PTRACE(1, __func__ );
  PAssert(0, PUnimplementedFunction);
   return false;
}

BOOL PSoundChannelCoreAudio::Read(void *buf,
              PINDEX len)
{
   PTRACE(5, "Read called with len " << len);

   if(state < setbuffer_){
      PTRACE(1, __func__ << " Please initialize device first");
      return FALSE;
   }

	pthread_mutex_lock(&GetIsMuteMutex());
	if(isMute() && state != mute_){
		PTRACE(2, __func__ << "muting the " << direction << " device");
		state = mute_;
		OSStatus err = AudioOutputUnitStop(mAudioUnit); 
		checkStatus(err);
		/* isMute() => state==mute */   
	}

   if (mDeviceID == kAudioDeviceDummy || isMute()) {
      lastReadCount =  len; 
      bzero(buf, len);
  
      // we are working with non-interleaved or mono
      UInt32 nr_samples = len / pwlibASBD.mBytesPerFrame; 
      usleep(UInt32(nr_samples/pwlibASBD.mSampleRate * 1000000)); // 10E-6 [s]
		pthread_mutex_unlock(&GetIsMuteMutex());
      return TRUE;  
   }

   // Start the device before draining data or the thread might be locked 
	// on an empty buffer and never wake up, because no device is filling
	// with data
   if(state == setbuffer_ || (state == mute_ && !isMute())){
      state = running_;
      PTRACE(2, "Starting " << direction << " device.");
		OSStatus err = AudioOutputUnitStart(mAudioUnit);
		checkStatus(err);
   }
	pthread_mutex_unlock(&GetIsMuteMutex());

   lastReadCount = mCircularBuffer->Drain((char*)buf, len, true);
   return (TRUE);
}


BOOL PSoundChannelCoreAudio::RecordSound(PSound & sound)
{
   PTRACE(1, __func__ );
  PAssert(0, PUnimplementedFunction);
   return false;
}

BOOL PSoundChannelCoreAudio::RecordFile(const PFilePath & file)
{
   PTRACE(1, __func__ );
  PAssert(0, PUnimplementedFunction);
   return false;
}

BOOL PSoundChannelCoreAudio::StartRecording()
{
   if(state != setbuffer_){
      PTRACE(1, __func__ << " Initialize the device first");
      return FALSE;
   }

	pthread_mutex_lock(&GetIsMuteMutex());
   if(state == setbuffer_ || (state == mute_ && !isMute())  ){
      state = running_;
      PTRACE(2,__func__ <<  "Starting " << direction << " device.");
      OSStatus err = AudioOutputUnitStart(mAudioUnit);
      checkStatus(err);
   }
	pthread_mutex_unlock(&GetIsMuteMutex());
   return false;
}

BOOL PSoundChannelCoreAudio::isRecordBufferFull()
{
   PAssert(direction == Recorder, PInvalidParameter);
   if(state != setbuffer_){
      PTRACE(1, __func__ << " Initialize the device first");
      return FALSE;
   }
   
   return (mCircularBuffer->size() > bufferSizeBytes);
}

BOOL PSoundChannelCoreAudio::AreAllRecordBuffersFull()
{
   PAssert(direction == Recorder, PInvalidParameter);
   if(state != setbuffer_){
      PTRACE(1, __func__ << " Initialize the device first");
      return FALSE;
   }

   return (mCircularBuffer->Full());
}

BOOL PSoundChannelCoreAudio::WaitForRecordBufferFull()
{
   PTRACE(1, __func__ );
  PAssert(0, PUnimplementedFunction);
  if (os_handle < 0) {
    return FALSE;
  }

  return PXSetIOBlock(PXReadBlock, readTimeout);
}

BOOL PSoundChannelCoreAudio::WaitForAllRecordBuffersFull()
{
   PTRACE(1, __func__ );
   PAssert(0, PUnimplementedFunction);
   return false;
}


// End of file

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -