2017-02-02 17:24:40 +01:00
|
|
|
//
|
|
|
|
// libtgvoip is free and unencumbered public domain software.
|
|
|
|
// For more information, see http://unlicense.org or the UNLICENSE file
|
|
|
|
// you should have received with this source code distribution.
|
|
|
|
//
|
|
|
|
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include "AudioOutputAudioUnit.h"
|
|
|
|
#include "../../logging.h"
|
|
|
|
#include "AudioUnitIO.h"
|
|
|
|
|
|
|
|
#define BUFFER_SIZE 960
|
|
|
|
const int8_t permutation[33]={0,1,2,3,4,4,5,5,5,5,6,6,6,6,6,7,7,7,7,8,8,8,9,9,9,9,9,9,9,9,9,9,9};
|
|
|
|
|
2017-04-28 13:17:56 +02:00
|
|
|
using namespace tgvoip;
|
|
|
|
using namespace tgvoip::audio;
|
|
|
|
|
2017-08-01 19:17:44 +02:00
|
|
|
AudioOutputAudioUnit::AudioOutputAudioUnit(std::string deviceID){
|
2017-02-02 17:24:40 +01:00
|
|
|
isPlaying=false;
|
|
|
|
remainingDataSize=0;
|
|
|
|
level=0.0;
|
2017-04-28 13:17:56 +02:00
|
|
|
this->io=AudioUnitIO::Get();
|
2017-08-01 19:17:44 +02:00
|
|
|
#if TARGET_OS_OSX
|
|
|
|
io->SetCurrentDevice(false, deviceID);
|
|
|
|
#endif
|
2017-02-02 17:24:40 +01:00
|
|
|
io->AttachOutput(this);
|
2017-08-01 19:17:44 +02:00
|
|
|
failed=io->IsFailed();
|
2017-02-02 17:24:40 +01:00
|
|
|
}
|
|
|
|
|
2017-04-28 13:17:56 +02:00
|
|
|
AudioOutputAudioUnit::~AudioOutputAudioUnit(){
|
2017-02-02 17:24:40 +01:00
|
|
|
io->DetachOutput();
|
2017-04-28 13:17:56 +02:00
|
|
|
AudioUnitIO::Release();
|
2017-02-02 17:24:40 +01:00
|
|
|
}
|
|
|
|
|
2017-04-28 13:17:56 +02:00
|
|
|
void AudioOutputAudioUnit::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_t channels){
|
2017-02-02 17:24:40 +01:00
|
|
|
io->Configure(sampleRate, bitsPerSample, channels);
|
|
|
|
}
|
|
|
|
|
2017-04-28 13:17:56 +02:00
|
|
|
bool AudioOutputAudioUnit::IsPhone(){
|
2017-02-02 17:24:40 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-04-28 13:17:56 +02:00
|
|
|
void AudioOutputAudioUnit::EnableLoudspeaker(bool enabled){
|
2017-02-02 17:24:40 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2017-04-28 13:17:56 +02:00
|
|
|
void AudioOutputAudioUnit::Start(){
|
2017-02-02 17:24:40 +01:00
|
|
|
isPlaying=true;
|
|
|
|
io->EnableOutput(true);
|
2017-08-01 19:17:44 +02:00
|
|
|
failed=io->IsFailed();
|
2017-02-02 17:24:40 +01:00
|
|
|
}
|
|
|
|
|
2017-04-28 13:17:56 +02:00
|
|
|
void AudioOutputAudioUnit::Stop(){
|
2017-02-02 17:24:40 +01:00
|
|
|
isPlaying=false;
|
|
|
|
io->EnableOutput(false);
|
|
|
|
}
|
|
|
|
|
2017-04-28 13:17:56 +02:00
|
|
|
bool AudioOutputAudioUnit::IsPlaying(){
|
2017-02-02 17:24:40 +01:00
|
|
|
return isPlaying;
|
|
|
|
}
|
|
|
|
|
2017-04-28 13:17:56 +02:00
|
|
|
float AudioOutputAudioUnit::GetLevel(){
|
2017-02-02 17:24:40 +01:00
|
|
|
return level / 9.0;
|
|
|
|
}
|
|
|
|
|
2017-04-28 13:17:56 +02:00
|
|
|
void AudioOutputAudioUnit::HandleBufferCallback(AudioBufferList *ioData){
|
2017-02-02 17:24:40 +01:00
|
|
|
int i;
|
|
|
|
unsigned int k;
|
|
|
|
int16_t absVal=0;
|
|
|
|
for(i=0;i<ioData->mNumberBuffers;i++){
|
|
|
|
AudioBuffer buf=ioData->mBuffers[i];
|
|
|
|
if(!isPlaying){
|
|
|
|
memset(buf.mData, 0, buf.mDataByteSize);
|
|
|
|
return;
|
|
|
|
}
|
2017-09-07 22:02:22 +02:00
|
|
|
#if TARGET_OS_OSX
|
|
|
|
while(remainingDataSize<buf.mDataByteSize/2){
|
|
|
|
assert(remainingDataSize+BUFFER_SIZE*2<sizeof(remainingData));
|
2017-02-02 17:24:40 +01:00
|
|
|
InvokeCallback(remainingData+remainingDataSize, BUFFER_SIZE*2);
|
|
|
|
remainingDataSize+=BUFFER_SIZE*2;
|
|
|
|
}
|
2017-08-01 19:17:44 +02:00
|
|
|
float* dst=reinterpret_cast<float*>(buf.mData);
|
|
|
|
int16_t* src=reinterpret_cast<int16_t*>(remainingData);
|
|
|
|
for(k=0;k<buf.mDataByteSize/4;k++){
|
|
|
|
dst[k]=src[k]/(float)INT16_MAX;
|
|
|
|
}
|
|
|
|
remainingDataSize-=buf.mDataByteSize/2;
|
|
|
|
memmove(remainingData, remainingData+buf.mDataByteSize/2, remainingDataSize);
|
|
|
|
#else
|
2017-09-07 22:02:22 +02:00
|
|
|
while(remainingDataSize<buf.mDataByteSize){
|
|
|
|
assert(remainingDataSize+BUFFER_SIZE*2<sizeof(remainingData));
|
|
|
|
InvokeCallback(remainingData+remainingDataSize, BUFFER_SIZE*2);
|
|
|
|
remainingDataSize+=BUFFER_SIZE*2;
|
|
|
|
}
|
2017-02-02 17:24:40 +01:00
|
|
|
memcpy(buf.mData, remainingData, buf.mDataByteSize);
|
|
|
|
remainingDataSize-=buf.mDataByteSize;
|
|
|
|
memmove(remainingData, remainingData+buf.mDataByteSize, remainingDataSize);
|
2017-08-01 19:17:44 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/*unsigned int samples=buf.mDataByteSize/sizeof(int16_t);
|
2017-02-02 17:24:40 +01:00
|
|
|
for (k=0;k<samples;k++){
|
|
|
|
int16_t absolute=(int16_t)abs(*((int16_t *)buf.mData+k));
|
|
|
|
if (absolute>absVal)
|
|
|
|
absVal=absolute;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (absVal>absMax)
|
|
|
|
absMax=absVal;
|
|
|
|
|
|
|
|
count++;
|
|
|
|
if (count>=10) {
|
|
|
|
count=0;
|
|
|
|
|
|
|
|
short position=absMax/1000;
|
|
|
|
if (position==0 && absMax>250) {
|
|
|
|
position=1;
|
|
|
|
}
|
|
|
|
level=permutation[position];
|
|
|
|
absMax>>=2;
|
2017-08-01 19:17:44 +02:00
|
|
|
}*/
|
2017-02-02 17:24:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-01 19:17:44 +02:00
|
|
|
#if TARGET_OS_OSX
|
|
|
|
void AudioOutputAudioUnit::SetCurrentDevice(std::string deviceID){
|
|
|
|
io->SetCurrentDevice(false, deviceID);
|
|
|
|
}
|
|
|
|
#endif
|