📄 beaudio.cxx
字号:
{
// This function is called by the BMediaRecorder object whenever it has a buffer
// with recorded data ready.
DETECTVARS(buffer, size/2)
DETECTSOUND();
((CircularBuffer *)cookie)->Fill((const BYTE **)&buffer, &size);
}
////////////////////////////////////////////////////////////////////////////////
// PSoundChannelBeOS
// This defines the number of times we would like to be called per second
// to play/record data
#define PLAYRECFREQ 20
// Macro to let the default buffer size correspond neatly with the
// setting we put into the format.
#define DEFAULT_BUFSIZE(channels, rate, bits) 480
//((channels*rate*(bits/8))/PLAYRECFREQ)
PSoundChannelBeOS::PSoundChannelBeOS() :
mRecorder(NULL),
mPlayer(NULL),
mBuffer(NULL),
mNumBuffers(1),
mResampler(NULL)
{
PRINT(("default constructor"));
InternalSetBuffers(DEFAULT_BUFSIZE(1, 8000, 16),DEFAULT_BUFSIZE(1, 8000, 16)/2);
SetFormat(1, 8000, 16);
// Nothing else to do here. Notice that the channel is not open for
// playing/recording yet.
}
PSoundChannelBeOS::PSoundChannelBeOS(const PString & dev,
Directions dir,
unsigned numChannels,
unsigned sampleRate,
unsigned bitsPerSample) :
mRecorder(NULL),
mPlayer(NULL),
mBuffer(NULL),
mNumBuffers(1),
mResampler(NULL)
{
PRINT(("constructor %s %u %u %u", dir==Player ? "Player" : "Recorder", numChannels, sampleRate, bitsPerSample));
InternalSetBuffers(DEFAULT_BUFSIZE(numChannels, sampleRate, bitsPerSample), DEFAULT_BUFSIZE(numChannels, sampleRate, bitsPerSample)/2);
Open(dev, dir, numChannels, sampleRate, bitsPerSample);
// ignore result; user will need to find out whether this succeeds using IsOpen
}
PSoundChannelBeOS::~PSoundChannelBeOS()
{
PRINT((""));
Close(); // destroys player and recorder
InternalSetBuffers(0,0); // destroys buffer
}
static const PStringArray GetRecorderDevicesList(BMediaRecorder *Recorder)
{
// Array to hold the list.
PStringArray devlist;
BMediaRecorder* bRecorder = NULL;
if(Recorder != NULL)
bRecorder = Recorder;
#ifdef MEDIA_KIT_UPDATE
BMediaRecorder localRecorder("GetRecorderDevicesList");
bool result=true;
status_t status;
{
if(bRecorder == NULL)
{
bRecorder = &localRecorder;
}
if (bRecorder == NULL || bRecorder->InitCheck()!=B_OK)
{
PRINT(("Error constructing recorder to fetch device names"));
result=false;
}
}
if (result)
{
media_format format;
format.type = B_MEDIA_RAW_AUDIO;
format.u.raw_audio=media_raw_audio_format::wildcard;
// The resampler can only handle 16-bit audio
format.u.raw_audio.format=media_raw_audio_format::B_AUDIO_SHORT;
// Let the media recorder determine which sources are available
if ((status = bRecorder->FetchSources(format, false))!=B_OK)
{
PRINT(("Couldn't fetch BMediaRecorder sources; status=%d", status));
result=false;
}
}
if (result)
{
// Fetch the names of all output devices
media_format format;
BString outname;
for (int i=0; i< bRecorder->CountSources(); i++)
{
if ((status = bRecorder->GetSourceAt(i, &outname, &format))==B_OK)
{
PRINT(("Device found: %s", outname.String()));
devlist[i] = PString(outname.String());
}
else
{
PRINT(("error %d retrieving data for device %d", status, i));
result=false;
}
}
}
if (!result)
{
devlist.RemoveAll();
}
return devlist;
#else
// Media Kit is the only device
devlist[0] = "MediaKit";
return devlist;
#endif
}
PStringArray PSoundChannelBeOS::GetDeviceNames(Directions dir)
{
if (dir==Recorder)
{
return GetRecorderDevicesList(NULL);
}
else
{
// not supported yet
return PStringArray("MediaKit");
}
}
PString PSoundChannelBeOS::GetDefaultDevice(Directions dir)
{
if (dir==Recorder)
{
const PStringArray &devlist = GetRecorderDevicesList(NULL);
if (devlist.GetSize()!=0)
{
return devlist[0];
}
else
{
return PString("MediaKit");
}
}
else
{
// not supported yet
return PString("MediaKit");
}
}
BOOL PSoundChannelBeOS::OpenPlayer(void)
{
// We're using cascaded "if result"s here for clarity
BOOL result = TRUE;
#ifdef FILEDUMP
media_format format;
format.type=B_MEDIA_RAW_AUDIO;
memcpy(&format.u.raw_audio, &mFormat, sizeof(mFormat));
delete playwriter;
playwriter=new BAudioFileWriter("play.wav", format, 441000);
#endif
// Must have a buffer
if (!mBuffer)
{
result = FALSE;
PRINT(("Trying to open as player without setting buffers first"));
}
if (result)
{
// Create the player
//was: mPlayer=new BSoundPlayer(&mFormat, NULL, PlayBuffer, NULL, mBuffer);
mPlayer = new BSoundPlayer(
&mFormat,
NULL,
PlayBuffer,
NULL,
mBuffer);
if ((mPlayer == NULL) || (mPlayer->InitCheck() != B_OK))
{
result = FALSE;
PRINT(("Couldn't construct player"));
}
}
if (result)
{
// Start the player
if (mPlayer->Start() != B_OK)
{
result = FALSE;
PRINT(("Couldn't start the player"));
}
}
if (result)
{
// Enable the fetching of data by PlayBuffer
mPlayer->SetHasData(true);
}
PRINT(("Returning %s", result?"success":"failure"));
return result;
}
BOOL PSoundChannelBeOS::OpenRecorder(const PString &dev)
{
// We're using cascaded "if result"s here for clarity
BOOL result=TRUE;
{
if (!mBuffer)
{
result=FALSE;
PRINT(("Trying to open as recorder without setting buffers first"));
}
}
if (result)
{
// Create the recorder
mRecorder=new BMediaRecorder("PWLIB PSoundChannel recorder");
if ((mRecorder==NULL) || (mRecorder->InitCheck()!=B_OK))
{
result=FALSE;
PRINT(("Couldn't construct recorder"));
}
}
#ifdef MEDIA_KIT_UPDATE
int32 sourceindex;
if (result)
{
// Find the specified device in the list of input devices
PINDEX x=GetRecorderDevicesList(mRecorder).GetStringsIndex(dev);
if (x==P_MAX_INDEX)
{
result=FALSE;
PRINT(("Couldn't find device %s in the list",(const char *)dev));
}
else
{
sourceindex=(int32)x;
}
}
#ifdef _DEBUG
if (result)
{
// Get information for the device
BString outname;
media_format xformat;
status_t err;
if ((err=mRecorder->GetSourceAt(sourceindex, &outname, &xformat))==B_OK)
{
PRINT(("%s", outname.String()));
PRINT((" type %d", (int)xformat.type));
PRINT((" AudioFormat 0x%X", (int)xformat.AudioFormat()));
PRINT((" u.raw_audio:"));
PRINT((" frame_rate: %f", xformat.u.raw_audio.frame_rate));
PRINT((" channel_count: %d", xformat.u.raw_audio.channel_count));
PRINT((" byte_order: %d", xformat.u.raw_audio.byte_order));
PRINT((" buffer_size: %d", xformat.u.raw_audio.buffer_size));
}
else
{
result=FALSE;
PRINT(("couldn't get details for source %d: err=0x%X",sourceindex,err));
}
}
#endif
if (result)
{
// Try to connect to the source
if (mRecorder->ConnectSourceAt(sourceindex)!=B_OK)
{
result=FALSE;
PRINT(("Couldn't connect BMediaRecorder to source"));
}
}
#else
if (result)
{
// Connect the recorder to the default input device
media_format format;
format.type=B_MEDIA_RAW_AUDIO;
format.u.raw_audio=media_raw_audio_format::wildcard;
// The resampler can only handle 16-bit audio
format.u.raw_audio.format=media_raw_audio_format::B_AUDIO_SHORT;
if (mRecorder->Connect(format,0)!=B_OK)
{
result=FALSE;
PRINT(("couldn't connect the recorder to the default source"));
}
}
#endif
if (result)
{
// Create resampler
media_format format=mRecorder->Format();
delete mResampler;
mResampler=new Resampler(
format.u.raw_audio.frame_rate,
mFormat.frame_rate,
format.u.raw_audio.channel_count,
mFormat.channel_count,
0,
2);
#ifdef FILEDUMP
{
media_format format;
format.type=B_MEDIA_RAW_AUDIO;
memcpy(&format.u.raw_audio, &mFormat, sizeof(mFormat));
delete recwriter;
recwriter=new BAudioFileWriter("record.wav", format);
}
#endif
// If the current buffer is not a resamplin buffer, re-create it
ResamplingBuffer *buf=dynamic_cast<ResamplingBuffer*>(mBuffer);
if (buf==NULL)
{
PRINT(("re-creating buffer"));
CircularBuffer *old=mBuffer;
mBuffer=new ResamplingBuffer(mResampler, old);
delete old;
}
else
{
buf->SetResampler(mResampler);
}
}
if (result)
{
// Set the hook function to our data processing function
PRINT(("Setting buffer hook, cookie=%p",mBuffer));
if (mRecorder->SetBufferHook(RecordBuffer, mBuffer)!=B_OK)
{
result=FALSE;
PRINT(("Couldn't set buffer hook on BMediaRecorder"));
}
}
// If something went wrong, delete the recorder.
if (!result)
{
if (mRecorder)
{
delete mRecorder;
mRecorder=NULL;
}
}
return result;
}
BOOL PSoundChannelBeOS::Open(const PString & dev,
Directions dir,
unsigned numChannels,
unsigned sampleRate,
unsigned bitsPerSample)
{
// We're using cascaded "if result"s here for clarity
BOOL result = TRUE;
PRINT(("%s %u %u %u", dir==Player?"Player":"Recorder", numChannels, sampleRate, bitsPerSample));
// Close the channel first, just in case
Close();
// Initialize the format struct, necessary to create player or recorder
if (!SetFormat(numChannels, sampleRate, bitsPerSample))
{
result = FALSE;
PRINT(("Couldn't set format"));
}
if (result)
{
switch (dir)
{
case Player:
PRINT(("... trying to open player"));
result=OpenPlayer();
break;
case Recorder:
PRINT(("...trying to open recorder"));
result=OpenRecorder(dev);
break;
default:
PRINT(("Unknown direction parameter"));
result=FALSE;
}
}
if (!result)
{
// If anything went wrong, clean up
PRINT(("... can't open, cleaning up"));
Close();
}
::snooze(1*1000*1000);
PRINT(("Returning %s", result?"success":"failure"));
return result;
}
BOOL PSoundChannelBeOS::Abort()
{
return FALSE;
}
BOOL PSoundChannelBeOS::SetFormat(unsigned numChannels,
unsigned sampleRate,
unsigned bitsPerSample)
{
PRINT(("%u %u %u", numChannels, sampleRate, bitsPerSample));
// NOTE: all constructors should call this to initialize
// the local members
// Do NOT call the function with any parameter set to 0!
// The function only fails if the channel is open.
// This is because the player or recorder needs to be re-created when the
// format changes.
if (IsOpen())
{
PRINT(("Not allowed to set format on open channel"));
return FALSE;
}
// Initialize the format struct
// The numbers of bits that we support here are 8, 16 or 32 bits (signed),
// results for other sizes are not defined.
mFormat = media_raw_audio_format::wildcard;
mFormat.frame_rate=(float)sampleRate;
mFormat.channel_count=numChannels;
mFormat.format=(bitsPerSample / 8) & 0xF;
mFormat.byte_order=B_HOST_IS_BENDIAN ? B_MEDIA_BIG_ENDIAN : B_MEDIA_LITTLE_ENDIAN;
mFormat.buffer_size=DEFAULT_BUFSIZE(numChannels, sampleRate, bitsPerSample);
return TRUE;
}
unsigned PSoundChannelBeOS::GetChannels() const
{
return mFormat.channel_count;
}
unsigned PSoundChannelBeOS::GetSampleRate() const
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -