work in progress: use one thread per connected channel, and a BList of BBuffer * to avoid dropping them. Disabled early buffer recycling as latency calculation is still broken. I can now play something without missing buffers.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25898 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -33,6 +33,13 @@
|
|||||||
|
|
||||||
#define ENABLE_REC 1
|
#define ENABLE_REC 1
|
||||||
|
|
||||||
|
// timeout in OpenSoundNode::RunThread()
|
||||||
|
#define MIN_SNOOZING 2000
|
||||||
|
|
||||||
|
// pretend we don't drift
|
||||||
|
#define DISABLE_DRIFT 1
|
||||||
|
|
||||||
|
|
||||||
/* bit mask of supported formats for raw_audio */
|
/* bit mask of supported formats for raw_audio */
|
||||||
/* also used to mark the raw_audio node input&outputs */
|
/* also used to mark the raw_audio node input&outputs */
|
||||||
//XXX: _OE ?
|
//XXX: _OE ?
|
||||||
|
|||||||
@@ -193,6 +193,25 @@ status_t OpenSoundDeviceEngine::UpdateInfo(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bigtime_t OpenSoundDeviceEngine::PlaybackLatency(void)
|
||||||
|
{
|
||||||
|
bigtime_t latency;
|
||||||
|
int delay;
|
||||||
|
delay = GetODelay();
|
||||||
|
delay = 0; //XXX
|
||||||
|
latency = ((double)delay * 1000000LL
|
||||||
|
/ (fMediaFormat.u.raw_audio.channel_count * fMediaFormat.u.raw_audio.frame_rate
|
||||||
|
* (fMediaFormat.AudioFormat() & media_raw_audio_format::B_AUDIO_SIZE_MASK)));
|
||||||
|
PRINT(("PlaybackLatency: odelay %d latency %Ld card %Ld\n", delay, latency, CardLatency()));
|
||||||
|
latency += CardLatency();
|
||||||
|
return latency;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bigtime_t OpenSoundDeviceEngine::RecordingLatency(void)
|
||||||
|
{
|
||||||
|
return 0LL; //XXX
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int OpenSoundDeviceEngine::GetChannels(void)
|
int OpenSoundDeviceEngine::GetChannels(void)
|
||||||
@@ -307,6 +326,108 @@ size_t OpenSoundDeviceEngine::GetOSpace(audio_buf_info *info)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int64
|
||||||
|
OpenSoundDeviceEngine::GetCurrentIPtr(int32 *fifoed, oss_count_t *info)
|
||||||
|
{
|
||||||
|
oss_count_t ocount;
|
||||||
|
count_info cinfo;
|
||||||
|
CALLED();
|
||||||
|
if (!info)
|
||||||
|
info = &ocount;
|
||||||
|
memset(info, 0, sizeof(oss_count_t));
|
||||||
|
if (!(fOpenMode & OPEN_READ))
|
||||||
|
return 0;
|
||||||
|
if (ioctl(fFD, SNDCTL_DSP_CURRENT_IPTR, info, sizeof(oss_count_t)) < 0) {
|
||||||
|
PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n",
|
||||||
|
__FUNCTION__, "SNDCTL_DSP_CURRENT_IPTR", strerror(errno)));
|
||||||
|
//return EIO;
|
||||||
|
// fallback: try GET*PTR
|
||||||
|
if (ioctl(fFD, SNDCTL_DSP_GETIPTR, &cinfo, sizeof(count_info)) < 0) {
|
||||||
|
PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n",
|
||||||
|
__FUNCTION__, "SNDCTL_DSP_GETIPTR", strerror(errno)));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// it's probably wrong...
|
||||||
|
info->samples = cinfo.bytes / (fMediaFormat.u.raw_audio.channel_count
|
||||||
|
* (fMediaFormat.AudioFormat() & media_raw_audio_format::B_AUDIO_SIZE_MASK));
|
||||||
|
info->fifo_samples = 0;
|
||||||
|
}
|
||||||
|
PRINT(("OpenSoundDeviceEngine::%s: IPTR: { samples=%Ld, fifo_samples=%d }\n", __FUNCTION__, info->samples, info->fifo_samples));
|
||||||
|
if (fifoed)
|
||||||
|
*fifoed = info->fifo_samples;
|
||||||
|
return info->samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int64
|
||||||
|
OpenSoundDeviceEngine::GetCurrentOPtr(int32 *fifoed, oss_count_t *info)
|
||||||
|
{
|
||||||
|
oss_count_t ocount;
|
||||||
|
count_info cinfo;
|
||||||
|
CALLED();
|
||||||
|
if (!info)
|
||||||
|
info = &ocount;
|
||||||
|
memset(info, 0, sizeof(oss_count_t));
|
||||||
|
if (!(fOpenMode & OPEN_WRITE))
|
||||||
|
return 0;
|
||||||
|
if (ioctl(fFD, SNDCTL_DSP_CURRENT_OPTR, info, sizeof(oss_count_t)) < 0) {
|
||||||
|
PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n",
|
||||||
|
__FUNCTION__, "SNDCTL_DSP_CURRENT_OPTR", strerror(errno)));
|
||||||
|
//return EIO;
|
||||||
|
// fallback: try GET*PTR
|
||||||
|
if (ioctl(fFD, SNDCTL_DSP_GETOPTR, &cinfo, sizeof(count_info)) < 0) {
|
||||||
|
PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n",
|
||||||
|
__FUNCTION__, "SNDCTL_DSP_GETOPTR", strerror(errno)));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// it's probably wrong...
|
||||||
|
info->samples = cinfo.bytes / (fMediaFormat.u.raw_audio.channel_count
|
||||||
|
* (fMediaFormat.AudioFormat() & media_raw_audio_format::B_AUDIO_SIZE_MASK));
|
||||||
|
info->fifo_samples = 0;
|
||||||
|
}
|
||||||
|
//PRINT(("OpenSoundDeviceEngine::%s: OPTR: { samples=%Ld, fifo_samples=%d }\n", __FUNCTION__, info->samples, info->fifo_samples));
|
||||||
|
if (fifoed)
|
||||||
|
*fifoed = info->fifo_samples;
|
||||||
|
return info->samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
OpenSoundDeviceEngine::GetIOverruns()
|
||||||
|
{
|
||||||
|
audio_errinfo info;
|
||||||
|
CALLED();
|
||||||
|
memset(&info, 0, sizeof(info));
|
||||||
|
if (!(fOpenMode & OPEN_WRITE))
|
||||||
|
return 0;
|
||||||
|
if (ioctl(fFD, SNDCTL_DSP_GETERROR, &info, sizeof(info)) < 0) {
|
||||||
|
PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n",
|
||||||
|
__FUNCTION__, "SNDCTL_DSP_GETERROR", strerror(errno)));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
PRINT(("OpenSoundDeviceEngine::%s: IOVERRUNS: { overruns=%d }\n", __FUNCTION__, info.rec_overruns));
|
||||||
|
return info.rec_overruns;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
OpenSoundDeviceEngine::GetOUnderruns()
|
||||||
|
{
|
||||||
|
audio_errinfo info;
|
||||||
|
CALLED();
|
||||||
|
memset(&info, 0, sizeof(info));
|
||||||
|
if (!(fOpenMode & OPEN_WRITE))
|
||||||
|
return 0;
|
||||||
|
if (ioctl(fFD, SNDCTL_DSP_GETERROR, &info, sizeof(info)) < 0) {
|
||||||
|
PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n",
|
||||||
|
__FUNCTION__, "SNDCTL_DSP_GETERROR", strerror(errno)));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
//PRINT(("OpenSoundDeviceEngine::%s: OUNDERRUNS: { underruns=%d }\n", __FUNCTION__, info.play_underruns));
|
||||||
|
return info.play_underruns;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int OpenSoundDeviceEngine::GetODelay(void)
|
int OpenSoundDeviceEngine::GetODelay(void)
|
||||||
{
|
{
|
||||||
//CALLED();
|
//CALLED();
|
||||||
@@ -340,6 +461,12 @@ status_t OpenSoundDeviceEngine::StartRecording(void)
|
|||||||
|
|
||||||
int64 OpenSoundDeviceEngine::PlayedFramesCount(void)
|
int64 OpenSoundDeviceEngine::PlayedFramesCount(void)
|
||||||
{
|
{
|
||||||
|
int64 played;
|
||||||
|
int32 fifoed;
|
||||||
|
played = GetCurrentOPtr(&fifoed);
|
||||||
|
//played += fifoed;
|
||||||
|
//return played;
|
||||||
|
fPlayedFramesCount = played - fifoed;
|
||||||
return fPlayedFramesCount;//XXX
|
return fPlayedFramesCount;//XXX
|
||||||
return fPlayedFramesCount - (GetODelay() / (fMediaFormat.u.raw_audio.channel_count
|
return fPlayedFramesCount - (GetODelay() / (fMediaFormat.u.raw_audio.channel_count
|
||||||
* (fMediaFormat.AudioFormat() & media_raw_audio_format::B_AUDIO_SIZE_MASK)));
|
* (fMediaFormat.AudioFormat() & media_raw_audio_format::B_AUDIO_SIZE_MASK)));
|
||||||
@@ -443,8 +570,10 @@ status_t OpenSoundDeviceEngine::AcceptFormatFor(int fmt, media_format &format, b
|
|||||||
{
|
{
|
||||||
status_t err;
|
status_t err;
|
||||||
int afmt = 0;
|
int afmt = 0;
|
||||||
|
char buf[1024];
|
||||||
CALLED();
|
CALLED();
|
||||||
fmt &= rec ? Info()->iformats : Info()->oformats;
|
fmt &= rec ? Info()->iformats : Info()->oformats;
|
||||||
|
|
||||||
if (fmt == 0)
|
if (fmt == 0)
|
||||||
return B_MEDIA_BAD_FORMAT;
|
return B_MEDIA_BAD_FORMAT;
|
||||||
media_format wc;
|
media_format wc;
|
||||||
@@ -540,12 +669,12 @@ status_t OpenSoundDeviceEngine::AcceptFormatFor(int fmt, media_format &format, b
|
|||||||
raw.buffer_size = DEFAULT_BUFFER_SIZE;
|
raw.buffer_size = DEFAULT_BUFFER_SIZE;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
PRINT(("%s: unknown media type\n", __FUNCTION__));
|
||||||
Close();
|
Close();
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
// cache it
|
// cache it
|
||||||
fMediaFormat = format;
|
fMediaFormat = format;
|
||||||
char buf[1024];
|
|
||||||
string_for_format(format, buf, 1024);
|
string_for_format(format, buf, 1024);
|
||||||
PRINT(("%s: %s\n", __FUNCTION__, buf));
|
PRINT(("%s: %s\n", __FUNCTION__, buf));
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -676,3 +805,4 @@ status_t OpenSoundDeviceEngine::SpecializeFormatFor(int fmt, media_format &forma
|
|||||||
PRINT(("%s: %s\n", __FUNCTION__, buf));
|
PRINT(("%s: %s\n", __FUNCTION__, buf));
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,9 @@ virtual ssize_t Write(const void *buffer, size_t size);
|
|||||||
status_t UpdateInfo();
|
status_t UpdateInfo();
|
||||||
// shortcuts
|
// shortcuts
|
||||||
int Caps() const { return fAudioInfo.caps; };
|
int Caps() const { return fAudioInfo.caps; };
|
||||||
int Latency() const { return fAudioInfo.latency; };
|
bigtime_t CardLatency(void) const { return (fAudioInfo.latency<0) ? 0 : fAudioInfo.latency; };
|
||||||
|
bigtime_t PlaybackLatency(void);
|
||||||
|
bigtime_t RecordingLatency(void);
|
||||||
|
|
||||||
|
|
||||||
int GetChannels(void);
|
int GetChannels(void);
|
||||||
@@ -55,10 +57,16 @@ virtual ssize_t Write(const void *buffer, size_t size);
|
|||||||
size_t GetISpace(audio_buf_info *info=NULL);
|
size_t GetISpace(audio_buf_info *info=NULL);
|
||||||
size_t GetOSpace(audio_buf_info *info=NULL);
|
size_t GetOSpace(audio_buf_info *info=NULL);
|
||||||
|
|
||||||
|
int64 GetCurrentIPtr(int32 *fifoed=NULL, oss_count_t *info=NULL);
|
||||||
|
int64 GetCurrentOPtr(int32 *fifoed=NULL, oss_count_t *info=NULL);
|
||||||
|
|
||||||
|
int32 GetIOverruns();
|
||||||
|
int32 GetOUnderruns();
|
||||||
|
|
||||||
int GetODelay(void);
|
int GetODelay(void);
|
||||||
|
|
||||||
status_t StartRecording(void);
|
status_t StartRecording(void);
|
||||||
|
|
||||||
int64 PlayedFramesCount(void);
|
int64 PlayedFramesCount(void);
|
||||||
bigtime_t PlayedRealTime(void);
|
bigtime_t PlayedRealTime(void);
|
||||||
|
|
||||||
|
|||||||
@@ -44,12 +44,13 @@
|
|||||||
#include <Buffer.h>
|
#include <Buffer.h>
|
||||||
#include <ParameterWeb.h>
|
#include <ParameterWeb.h>
|
||||||
#include <MediaRoster.h>
|
#include <MediaRoster.h>
|
||||||
#include <limits.h>
|
|
||||||
#include <MediaDefs.h>
|
#include <MediaDefs.h>
|
||||||
#include <Message.h>
|
#include <Message.h>
|
||||||
#include <Debug.h>
|
#include <Debug.h>
|
||||||
#include <Autolock.h>
|
#include <Autolock.h>
|
||||||
#include <String.h>
|
#include <String.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
#include "OpenSoundNode.h"
|
#include "OpenSoundNode.h"
|
||||||
#include "driver_io.h"
|
#include "driver_io.h"
|
||||||
@@ -73,13 +74,15 @@ const char * multi_string[] =
|
|||||||
node_input::node_input(media_input &input, media_format format)
|
node_input::node_input(media_input &input, media_format format)
|
||||||
{
|
{
|
||||||
CALLED();
|
CALLED();
|
||||||
|
fNode = NULL;
|
||||||
fEngineId = -1;
|
fEngineId = -1;
|
||||||
fRealEngine = NULL;
|
fRealEngine = NULL;
|
||||||
fAFmt = 0;
|
fAFmt = 0;
|
||||||
fInput = input;
|
fInput = input;
|
||||||
fPreferredFormat = format;
|
fPreferredFormat = format;
|
||||||
fBufferCycle = 1;
|
fBufferCycle = 1;
|
||||||
fBuffer = NULL;
|
//fBuffer = NULL;
|
||||||
|
fThread = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
node_input::~node_input()
|
node_input::~node_input()
|
||||||
@@ -92,12 +95,14 @@ node_output::node_output(media_output &output, media_format format)
|
|||||||
fOutputEnabled(true)
|
fOutputEnabled(true)
|
||||||
{
|
{
|
||||||
CALLED();
|
CALLED();
|
||||||
|
fNode = NULL;
|
||||||
fEngineId = -1;
|
fEngineId = -1;
|
||||||
fRealEngine = NULL;
|
fRealEngine = NULL;
|
||||||
fAFmt = 0;
|
fAFmt = 0;
|
||||||
fOutput = output;
|
fOutput = output;
|
||||||
fPreferredFormat = format;
|
fPreferredFormat = format;
|
||||||
fBufferCycle = 1;
|
fBufferCycle = 1;
|
||||||
|
fThread = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
node_output::~node_output()
|
node_output::~node_output()
|
||||||
@@ -115,7 +120,7 @@ OpenSoundNode::~OpenSoundNode(void)
|
|||||||
CALLED();
|
CALLED();
|
||||||
fAddOn->GetConfigurationFor(this, NULL);
|
fAddOn->GetConfigurationFor(this, NULL);
|
||||||
|
|
||||||
StopThread();
|
//StopThread();
|
||||||
BMediaEventLooper::Quit();
|
BMediaEventLooper::Quit();
|
||||||
|
|
||||||
fWeb = NULL;
|
fWeb = NULL;
|
||||||
@@ -283,6 +288,7 @@ void OpenSoundNode::NodeRegistered(void)
|
|||||||
currentInput->fChannelId = i;//XXX:REMOVEME fDevice->MD.channels[i].channel_id;
|
currentInput->fChannelId = i;//XXX:REMOVEME fDevice->MD.channels[i].channel_id;
|
||||||
currentInput->fEngineId = i;
|
currentInput->fEngineId = i;
|
||||||
currentInput->fAFmt = fmt;
|
currentInput->fAFmt = fmt;
|
||||||
|
currentInput->fNode = this;
|
||||||
fInputs.AddItem(currentInput);
|
fInputs.AddItem(currentInput);
|
||||||
|
|
||||||
currentInput->fInput.format.u.raw_audio.format = media_raw_audio_format::wildcard.format;
|
currentInput->fInput.format.u.raw_audio.format = media_raw_audio_format::wildcard.format;
|
||||||
@@ -332,6 +338,7 @@ void OpenSoundNode::NodeRegistered(void)
|
|||||||
currentOutput->fChannelId = i;//XXX:REMOVEME fDevice->MD.channels[i].channel_id;
|
currentOutput->fChannelId = i;//XXX:REMOVEME fDevice->MD.channels[i].channel_id;
|
||||||
currentOutput->fEngineId = i;
|
currentOutput->fEngineId = i;
|
||||||
currentOutput->fAFmt = fmt;
|
currentOutput->fAFmt = fmt;
|
||||||
|
currentOutput->fNode = this;
|
||||||
fOutputs.AddItem(currentOutput);
|
fOutputs.AddItem(currentOutput);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -553,11 +560,15 @@ status_t OpenSoundNode::GetLatencyFor(
|
|||||||
|
|
||||||
node_input *channel = FindInput(for_whom);
|
node_input *channel = FindInput(for_whom);
|
||||||
|
|
||||||
if(channel==NULL) {
|
if(channel==NULL || channel->fRealEngine==NULL) {
|
||||||
fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
|
fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
|
||||||
return B_MEDIA_BAD_DESTINATION;
|
return B_MEDIA_BAD_DESTINATION;
|
||||||
}
|
}
|
||||||
*out_latency = EventLatency();
|
*out_latency = EventLatency(); // mmu_man: that's the own node latency (1 buffer)
|
||||||
|
// add the OSS driver buffer's latency as well
|
||||||
|
*out_latency += channel->fRealEngine->PlaybackLatency();
|
||||||
|
PRINT(("############ OpenSoundNode::%s: EventLatency %Ld, OSS %Ld\n", __FUNCTION__, EventLatency(), channel->fRealEngine->PlaybackLatency()));
|
||||||
|
//*out_latency += MIN_SNOOZING;
|
||||||
*out_timesource = TimeSource()->ID();
|
*out_timesource = TimeSource()->ID();
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@@ -599,7 +610,8 @@ status_t OpenSoundNode::Connected(
|
|||||||
*out_input = channel->fInput;
|
*out_input = channel->fInput;
|
||||||
|
|
||||||
// we are sure the thread is started
|
// we are sure the thread is started
|
||||||
StartThread();
|
//StartThread();
|
||||||
|
StartPlayThread(channel);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@@ -619,7 +631,8 @@ void OpenSoundNode::Disconnected(
|
|||||||
fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
|
fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StopPlayThread(channel);
|
||||||
channel->fInput.source = media_source::null;
|
channel->fInput.source = media_source::null;
|
||||||
channel->fInput.format = channel->fPreferredFormat;
|
channel->fInput.format = channel->fPreferredFormat;
|
||||||
if (channel->fRealEngine)
|
if (channel->fRealEngine)
|
||||||
@@ -942,7 +955,8 @@ OpenSoundNode::Connect(status_t error, const media_source& source, const media_d
|
|||||||
engine->StartRecording();
|
engine->StartRecording();
|
||||||
|
|
||||||
// we are sure the thread is started
|
// we are sure the thread is started
|
||||||
StartThread();
|
//StartThread();
|
||||||
|
StartRecThread(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -959,6 +973,8 @@ OpenSoundNode::Disconnect(const media_source& what, const media_destination& whe
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StopRecThread(channel);
|
||||||
|
|
||||||
BAutolock L(fDevice->Locker());
|
BAutolock L(fDevice->Locker());
|
||||||
|
|
||||||
OpenSoundDeviceEngine *engine = channel->fRealEngine;
|
OpenSoundDeviceEngine *engine = channel->fRealEngine;
|
||||||
@@ -1129,26 +1145,49 @@ status_t OpenSoundNode::HandleBuffer(
|
|||||||
// who sent it to us
|
// who sent it to us
|
||||||
if ((RunMode() != B_OFFLINE) && // lateness doesn't matter in offline mode...
|
if ((RunMode() != B_OFFLINE) && // lateness doesn't matter in offline mode...
|
||||||
(RunMode() != B_RECORDING) && // ...or in recording mode
|
(RunMode() != B_RECORDING) && // ...or in recording mode
|
||||||
(how_early < 0LL))
|
(how_early < 0LL) && false /* XXX:DEBUG */)
|
||||||
{
|
{
|
||||||
//mLateBuffers++;
|
//mLateBuffers++;
|
||||||
NotifyLateProducer(channel->fInput.source, -how_early, perf_time);
|
NotifyLateProducer(channel->fInput.source, -how_early, perf_time);
|
||||||
fprintf(stderr," <- LATE BUFFER : %lli\n", how_early);
|
fprintf(stderr," <- LATE BUFFER : %lli\n", how_early);
|
||||||
buffer->Recycle();
|
buffer->Recycle();
|
||||||
|
release_sem(fBufferAvailableSem);
|
||||||
} else {
|
} else {
|
||||||
//WriteBuffer(buffer, *channel);
|
//WriteBuffer(buffer, *channel);
|
||||||
if(channel->fBuffer != NULL) {
|
|
||||||
|
fDevice->Locker()->Lock();
|
||||||
|
if (channel->fBuffers.CountItems() > 10) {
|
||||||
|
fDevice->Locker()->Unlock();
|
||||||
|
PRINT(("OpenSoundNode::HandleBuffer too many buffers, recycling\n"));
|
||||||
|
buffer->Recycle();
|
||||||
|
release_sem(fBufferAvailableSem);
|
||||||
|
} else {
|
||||||
|
//PRINT(("OpenSoundNode::HandleBuffer writing channelId : %i, how_early:%lli\n", channel->fChannelId, how_early));
|
||||||
|
channel->fBuffers.AddItem(buffer);
|
||||||
|
fDevice->Locker()->Unlock();
|
||||||
|
release_sem(fBufferAvailableSem);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if (channel->fBuffer != NULL) {
|
||||||
PRINT(("OpenSoundNode::HandleBuffer snoozing recycling channelId : %i, how_early:%lli\n", channel->fChannelId, how_early));
|
PRINT(("OpenSoundNode::HandleBuffer snoozing recycling channelId : %i, how_early:%lli\n", channel->fChannelId, how_early));
|
||||||
//channel->fBuffer->Recycle();
|
//channel->fBuffer->Recycle();
|
||||||
|
release_sem(fBufferAvailableSem);
|
||||||
snooze(100);
|
snooze(100);
|
||||||
if(channel->fBuffer != NULL)
|
if(channel->fBuffer != NULL) {
|
||||||
|
PRINT(("OpenSoundNode::HandleBuffer old buffer still there, recycling\n"));
|
||||||
buffer->Recycle();
|
buffer->Recycle();
|
||||||
else
|
//release_sem(fBufferAvailableSem);
|
||||||
|
} else {
|
||||||
channel->fBuffer = buffer;
|
channel->fBuffer = buffer;
|
||||||
|
release_sem(fBufferAvailableSem);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
//PRINT(("OpenSoundNode::HandleBuffer writing channelId : %i, how_early:%lli\n", channel->fChannelId, how_early));
|
//PRINT(("OpenSoundNode::HandleBuffer writing channelId : %i, how_early:%lli\n", channel->fChannelId, how_early));
|
||||||
channel->fBuffer = buffer;
|
channel->fBuffer = buffer;
|
||||||
|
release_sem(fBufferAvailableSem);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@@ -1247,7 +1286,7 @@ OpenSoundNode::TimeSourceOp(const time_source_op_info &op, void *_reserved)
|
|||||||
PRINT(("TimeSourceOp op B_TIMESOURCE_START\n"));
|
PRINT(("TimeSourceOp op B_TIMESOURCE_START\n"));
|
||||||
if (RunState() != BMediaEventLooper::B_STARTED) {
|
if (RunState() != BMediaEventLooper::B_STARTED) {
|
||||||
fTimeSourceStarted = true;
|
fTimeSourceStarted = true;
|
||||||
StartThread();
|
//StartThread();
|
||||||
|
|
||||||
media_timed_event startEvent(0, BTimedEventQueue::B_START);
|
media_timed_event startEvent(0, BTimedEventQueue::B_START);
|
||||||
EventQueue()->AddEvent(startEvent);
|
EventQueue()->AddEvent(startEvent);
|
||||||
@@ -1259,7 +1298,7 @@ OpenSoundNode::TimeSourceOp(const time_source_op_info &op, void *_reserved)
|
|||||||
media_timed_event stopEvent(0, BTimedEventQueue::B_STOP);
|
media_timed_event stopEvent(0, BTimedEventQueue::B_STOP);
|
||||||
EventQueue()->AddEvent(stopEvent);
|
EventQueue()->AddEvent(stopEvent);
|
||||||
fTimeSourceStarted = false;
|
fTimeSourceStarted = false;
|
||||||
StopThread();
|
//StopThread();
|
||||||
PublishTime(0, 0, 0);
|
PublishTime(0, 0, 0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1269,7 +1308,7 @@ OpenSoundNode::TimeSourceOp(const time_source_op_info &op, void *_reserved)
|
|||||||
media_timed_event stopEvent(0, BTimedEventQueue::B_STOP);
|
media_timed_event stopEvent(0, BTimedEventQueue::B_STOP);
|
||||||
EventQueue()->AddEvent(stopEvent);
|
EventQueue()->AddEvent(stopEvent);
|
||||||
fTimeSourceStarted = false;
|
fTimeSourceStarted = false;
|
||||||
StopThread();
|
//StopThread();
|
||||||
PublishTime(0, 0, 0);
|
PublishTime(0, 0, 0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -2044,19 +2083,43 @@ OpenSoundNode::PropagateParameterChanges(int from, int type, const char *id)
|
|||||||
// OpenSoundNode specific functions
|
// OpenSoundNode specific functions
|
||||||
// -------------------------------------------------------- //
|
// -------------------------------------------------------- //
|
||||||
|
|
||||||
|
#if 0
|
||||||
int32
|
int32
|
||||||
OpenSoundNode::RunThread()
|
OpenSoundNode::RunThread()
|
||||||
{
|
{
|
||||||
int32 i;
|
int32 i;
|
||||||
|
int32 bufferAvailReq = 1;
|
||||||
|
bigtime_t timeout = MIN_SNOOZING;
|
||||||
CALLED();
|
CALLED();
|
||||||
|
//set_thread_priority(find_thread(NULL), 5);//XXX:DEBUG
|
||||||
|
|
||||||
|
return 0; //XXX: REMOVE
|
||||||
|
|
||||||
while ( 1 ) {
|
while ( 1 ) {
|
||||||
|
status_t err;
|
||||||
|
bigtime_t before = system_time();
|
||||||
|
|
||||||
// XXX: use select() here when it gets implemented!
|
// XXX: use select() here when it gets implemented!
|
||||||
|
|
||||||
|
if (bufferAvailReq < 1)
|
||||||
|
bufferAvailReq = 1;
|
||||||
|
|
||||||
|
PRINT(("OpenSoundNode::RunThread: waiting for %d buffers, timeout %lld\n", bufferAvailReq, timeout));
|
||||||
|
|
||||||
//acquire buffer if any
|
//acquire buffer if any
|
||||||
if ( acquire_sem_etc( fBuffer_free, 1, B_RELATIVE_TIMEOUT, 0 ) == B_BAD_SEM_ID ) {
|
err = acquire_sem_etc( fBufferAvailableSem, bufferAvailReq, B_RELATIVE_TIMEOUT, timeout );
|
||||||
|
if (err == B_BAD_SEM_ID ) {
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
if (err == B_OK)
|
||||||
|
bufferAvailReq = 0;//1;
|
||||||
|
if (err == B_TIMED_OUT) {
|
||||||
|
PRINT(("OpenSoundNode::RunThread: acquire_sem timed out\n"));
|
||||||
|
bufferAvailReq = 0;//1;
|
||||||
|
} else {
|
||||||
|
PRINT(("OpenSoundNode::RunThread: acquire_sem done, waited %Ld\n", system_time() - before));
|
||||||
|
}
|
||||||
|
timeout = MIN_SNOOZING;
|
||||||
|
|
||||||
//PRINT(("OpenSoundNode::RunThread: RunState= %d, EventQ: %d events\n", RunState(), EventQueue()->EventCount()));
|
//PRINT(("OpenSoundNode::RunThread: RunState= %d, EventQ: %d events\n", RunState(), EventQueue()->EventCount()));
|
||||||
|
|
||||||
@@ -2082,7 +2145,8 @@ OpenSoundNode::RunThread()
|
|||||||
if (avail < 1)
|
if (avail < 1)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
#if 0
|
//engine->GetOUnderruns();
|
||||||
|
#if 1
|
||||||
// update the timesource
|
// update the timesource
|
||||||
if(input->fChannelId==0) {
|
if(input->fChannelId==0) {
|
||||||
//PRINT(("updating timesource\n"));
|
//PRINT(("updating timesource\n"));
|
||||||
@@ -2093,21 +2157,39 @@ OpenSoundNode::RunThread()
|
|||||||
if(input->fBuffer!=NULL) {
|
if(input->fBuffer!=NULL) {
|
||||||
if (avail < input->fBuffer->SizeUsed())
|
if (avail < input->fBuffer->SizeUsed())
|
||||||
continue;
|
continue;
|
||||||
//PRINT(("OpenSoundNode::RunThread: input[%d]: sending buffer\n", i));
|
PRINT(("OpenSoundNode::RunThread: input[%d]: sending buffer (%d bytes)\n", i, input->fBuffer->SizeUsed()));
|
||||||
|
|
||||||
|
{
|
||||||
|
bigtime_t tout; // = input->fBuffer->SizeUsed();
|
||||||
|
tout = abinfo.fragsize * abinfo.fragstotal - abinfo.bytes;
|
||||||
|
tout = tout * 1000000LL / (input->fInput.format.u.raw_audio.channel_count
|
||||||
|
* (input->fInput.format.AudioFormat() & media_raw_audio_format::B_AUDIO_SIZE_MASK)
|
||||||
|
* input->fInput.format.u.raw_audio.frame_rate);
|
||||||
|
if (tout && (tout < timeout)) {
|
||||||
|
//PRINT(("new timeout: %Ld\n", tout));
|
||||||
|
timeout = tout;
|
||||||
|
}
|
||||||
|
// let's try this...
|
||||||
|
//SendLatencyChange(input->fInput.source, input->fInput.destination, EventLatency()+tout);
|
||||||
|
}
|
||||||
FillNextBuffer(*input, input->fBuffer);
|
FillNextBuffer(*input, input->fBuffer);
|
||||||
input->fBuffer->Recycle();
|
input->fBuffer->Recycle();
|
||||||
input->fBuffer = NULL;
|
input->fBuffer = NULL;
|
||||||
|
bufferAvailReq++;
|
||||||
} else {
|
} else {
|
||||||
if (avail < abinfo.fragsize)
|
if (avail < abinfo.fragsize)
|
||||||
continue;
|
continue;
|
||||||
//XXX: write silence
|
//XXX: write silence
|
||||||
// write a nulled fragment
|
// write a nulled fragment
|
||||||
|
PRINT(("OpenSoundNode::RunThread: input[%d]: sending zeros\n", i));
|
||||||
|
//#ifdef WRITE_ZEROS
|
||||||
if(input->fInput.source != media_source::null)
|
if(input->fInput.source != media_source::null)
|
||||||
WriteZeros(*input, abinfo.fragsize);
|
WriteZeros(*input, abinfo.fragsize);
|
||||||
|
//#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 1
|
#if 0
|
||||||
// update the timesource
|
// update the timesource
|
||||||
if(input->fChannelId==0) {
|
if(input->fChannelId==0) {
|
||||||
//PRINT(("updating timesource\n"));
|
//PRINT(("updating timesource\n"));
|
||||||
@@ -2164,8 +2246,8 @@ OpenSoundNode::RunThread()
|
|||||||
fDevice->Locker()->Unlock();
|
fDevice->Locker()->Unlock();
|
||||||
|
|
||||||
//XXX
|
//XXX
|
||||||
snooze(5000);
|
//snooze(1000);
|
||||||
release_sem(fBuffer_free);//XXX
|
//release_sem(fBufferAvailableSem);//XXX
|
||||||
}
|
}
|
||||||
#if MA
|
#if MA
|
||||||
multi_buffer_info MBI;//, oldMBI;
|
multi_buffer_info MBI;//, oldMBI;
|
||||||
@@ -2175,7 +2257,7 @@ OpenSoundNode::RunThread()
|
|||||||
|
|
||||||
while ( 1 ) {
|
while ( 1 ) {
|
||||||
//acquire buffer if any
|
//acquire buffer if any
|
||||||
if ( acquire_sem_etc( fBuffer_free, 1, B_RELATIVE_TIMEOUT, 0 ) == B_BAD_SEM_ID ) {
|
if ( acquire_sem_etc( fBufferAvailableSem, 1, B_RELATIVE_TIMEOUT, 0 ) == B_BAD_SEM_ID ) {
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2227,7 +2309,7 @@ OpenSoundNode::RunThread()
|
|||||||
}
|
}
|
||||||
|
|
||||||
//mark buffer free
|
//mark buffer free
|
||||||
release_sem( fBuffer_free );
|
release_sem( fBufferAvailableSem );
|
||||||
} else {
|
} else {
|
||||||
//PRINT(("playback_buffer_cycle non ok input : %i\n", i));
|
//PRINT(("playback_buffer_cycle non ok input : %i\n", i));
|
||||||
}
|
}
|
||||||
@@ -2274,6 +2356,157 @@ OpenSoundNode::RunThread()
|
|||||||
#endif
|
#endif
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
OpenSoundNode::EnginePlayThread(node_input *input)
|
||||||
|
{
|
||||||
|
//int32 i;
|
||||||
|
CALLED();
|
||||||
|
//set_thread_priority(find_thread(NULL), 5);//XXX:DEBUG
|
||||||
|
signal(SIGUSR1, &_sig_handler_);
|
||||||
|
|
||||||
|
OpenSoundDeviceEngine *engine = input->fRealEngine;
|
||||||
|
if (!engine || !engine->InUse())
|
||||||
|
return B_NO_INIT;
|
||||||
|
// skip unconnected or non-busy engines
|
||||||
|
if (input->fInput.source == media_source::null
|
||||||
|
&& input->fChannelId == 0)
|
||||||
|
return B_NO_INIT;
|
||||||
|
// must be open for write
|
||||||
|
ASSERT (engine->OpenMode() & OPEN_WRITE);
|
||||||
|
|
||||||
|
do {
|
||||||
|
fDevice->Locker()->Lock();
|
||||||
|
|
||||||
|
audio_buf_info abinfo;
|
||||||
|
size_t avail = engine->GetOSpace(&abinfo);
|
||||||
|
//PRINT(("OpenSoundNode::EnginePlayThread: avail: %d\n", avail));
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
// TODO: do not assume channel 0 will always be running!
|
||||||
|
// update the timesource
|
||||||
|
if(input->fChannelId==0) {
|
||||||
|
//PRINT(("updating timesource\n"));
|
||||||
|
UpdateTimeSource(&abinfo, *input);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if 0
|
||||||
|
BBuffer *buffer = input->fBuffer;
|
||||||
|
input->fBuffer = NULL;
|
||||||
|
#endif
|
||||||
|
BBuffer *buffer = (BBuffer *)input->fBuffers.RemoveItem((int32)0);
|
||||||
|
|
||||||
|
fDevice->Locker()->Unlock();
|
||||||
|
if (input->fThread < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (buffer != NULL) {
|
||||||
|
//if (avail < input->fBuffer->SizeUsed())
|
||||||
|
// continue;
|
||||||
|
//PRINT(("OpenSoundNode::EnginePlayThread: input[%d]: sending buffer (%d bytes)\n", input->fChannelId, buffer->SizeUsed()));
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
{
|
||||||
|
bigtime_t tout; // = input->fBuffer->SizeUsed();
|
||||||
|
tout = abinfo.fragsize * abinfo.fragstotal - abinfo.bytes;
|
||||||
|
tout = tout * 1000000LL / (input->fInput.format.u.raw_audio.channel_count
|
||||||
|
* (input->fInput.format.AudioFormat() & media_raw_audio_format::B_AUDIO_SIZE_MASK)
|
||||||
|
* input->fInput.format.u.raw_audio.frame_rate);
|
||||||
|
if (tout && (tout < timeout)) {
|
||||||
|
//PRINT(("new timeout: %Ld\n", tout));
|
||||||
|
timeout = tout;
|
||||||
|
}
|
||||||
|
// let's try this...
|
||||||
|
//SendLatencyChange(input->fInput.source, input->fInput.destination, EventLatency()+tout);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
FillNextBuffer(*input, buffer);
|
||||||
|
buffer->Recycle();
|
||||||
|
} else {
|
||||||
|
//if (avail < abinfo.fragsize)
|
||||||
|
// continue;
|
||||||
|
//XXX: write silence
|
||||||
|
// write a nulled fragment
|
||||||
|
//PRINT(("OpenSoundNode::EnginePlayThread: input[%d]: sending zeros\n", input->fChannelId));
|
||||||
|
//#ifdef WRITE_ZEROS
|
||||||
|
if (input->fInput.source != media_source::null)
|
||||||
|
WriteZeros(*input, abinfo.fragsize);
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// update the timesource
|
||||||
|
if(input->fChannelId==0) {
|
||||||
|
//PRINT(("updating timesource\n"));
|
||||||
|
UpdateTimeSource(&abinfo, *input);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} while (input->fThread > -1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
OpenSoundNode::EngineRecThread(node_output *output)
|
||||||
|
{
|
||||||
|
int32 i;
|
||||||
|
CALLED();
|
||||||
|
//set_thread_priority(find_thread(NULL), 5);//XXX:DEBUG
|
||||||
|
signal(SIGUSR1, &_sig_handler_);
|
||||||
|
|
||||||
|
OpenSoundDeviceEngine *engine = output->fRealEngine;
|
||||||
|
if (!engine || !engine->InUse())
|
||||||
|
return B_NO_INIT;
|
||||||
|
// make sure we're both started *and* connected before delivering a buffer
|
||||||
|
if ((RunState() != BMediaEventLooper::B_STARTED) || (output->fOutput.destination == media_destination::null))
|
||||||
|
return B_NO_INIT;
|
||||||
|
|
||||||
|
// must be open for read
|
||||||
|
ASSERT (engine->OpenMode() & OPEN_READ);
|
||||||
|
#ifdef ENABLE_REC
|
||||||
|
|
||||||
|
fDevice->Locker()->Lock();
|
||||||
|
do {
|
||||||
|
audio_buf_info abinfo;
|
||||||
|
size_t avail = engine->GetISpace(&abinfo);
|
||||||
|
//PRINT(("OpenSoundNode::RunThread: I avail: %d\n", avail));
|
||||||
|
|
||||||
|
// skip if less than 1 buffer
|
||||||
|
//if (avail < output->fOutput.format.u.raw_audio.buffer_size)
|
||||||
|
// continue;
|
||||||
|
|
||||||
|
fDevice->Locker()->Unlock();
|
||||||
|
// Get the next buffer of data
|
||||||
|
BBuffer* buffer = FillNextBuffer(&abinfo, *output);
|
||||||
|
fDevice->Locker()->Lock();
|
||||||
|
|
||||||
|
if (buffer) {
|
||||||
|
// send the buffer downstream if and only if output is enabled
|
||||||
|
status_t err = B_ERROR;
|
||||||
|
if (output->fOutputEnabled)
|
||||||
|
err = SendBuffer(buffer, output->fOutput.destination);
|
||||||
|
//PRINT(("OpenSoundNode::RunThread: I avail: %d, OE %d, %s\n", avail, output->fOutputEnabled, strerror(err)));
|
||||||
|
if (err) {
|
||||||
|
buffer->Recycle();
|
||||||
|
} else {
|
||||||
|
// track how much media we've delivered so far
|
||||||
|
size_t nSamples = output->fOutput.format.u.raw_audio.buffer_size
|
||||||
|
/ (output->fOutput.format.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK);
|
||||||
|
output->fSamplesSent += nSamples;
|
||||||
|
//PRINT(("OpenSoundNode::%s: sent %d samples\n", __FUNCTION__, nSamples));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} while (output->fThread > -1);
|
||||||
|
fDevice->Locker()->Unlock();
|
||||||
|
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
OpenSoundNode::WriteZeros(node_input &input, size_t len)
|
OpenSoundNode::WriteZeros(node_input &input, size_t len)
|
||||||
@@ -2542,17 +2775,17 @@ OpenSoundNode::StartThread()
|
|||||||
//allocate buffer free semaphore
|
//allocate buffer free semaphore
|
||||||
int bufcount = MAX(fDevice->fFragments.fragstotal, 2);//XXX
|
int bufcount = MAX(fDevice->fFragments.fragstotal, 2);//XXX
|
||||||
|
|
||||||
// fBuffer_free = create_sem( fDevice->MBL.return_playback_buffers - 1, "multi_audio out buffer free" );
|
// fBufferAvailableSem = create_sem( fDevice->MBL.return_playback_buffers - 1, "multi_audio out buffer free" );
|
||||||
fBuffer_free = create_sem( bufcount - 1, "OpenSound out buffer free" );
|
fBufferAvailableSem = create_sem( bufcount - 1, "OpenSound out buffer free" );
|
||||||
|
|
||||||
if ( fBuffer_free < B_OK ) {
|
if ( fBufferAvailableSem < B_OK ) {
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
fThread = spawn_thread( _run_thread_, "OpenSound audio output", B_REAL_TIME_PRIORITY, this );
|
fThread = spawn_thread( _run_thread_, "OpenSound audio output", B_REAL_TIME_PRIORITY, this );
|
||||||
|
|
||||||
if ( fThread < B_OK ) {
|
if ( fThread < B_OK ) {
|
||||||
delete_sem( fBuffer_free );
|
delete_sem( fBufferAvailableSem );
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2564,11 +2797,101 @@ status_t
|
|||||||
OpenSoundNode::StopThread()
|
OpenSoundNode::StopThread()
|
||||||
{
|
{
|
||||||
CALLED();
|
CALLED();
|
||||||
delete_sem( fBuffer_free );
|
delete_sem( fBufferAvailableSem );
|
||||||
wait_for_thread( fThread, &fThread );
|
wait_for_thread( fThread, &fThread );
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status_t
|
||||||
|
OpenSoundNode::StartPlayThread(node_input *input)
|
||||||
|
{
|
||||||
|
CALLED();
|
||||||
|
BAutolock L(fDevice->Locker());
|
||||||
|
// the thread is already started ?
|
||||||
|
if (input->fThread > B_OK)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
//allocate buffer free semaphore
|
||||||
|
// int bufcount = MAX(fDevice->fFragments.fragstotal, 2);//XXX
|
||||||
|
|
||||||
|
// fBufferAvailableSem = create_sem( fDevice->MBL.return_playback_buffers - 1, "multi_audio out buffer free" );
|
||||||
|
// fBufferAvailableSem = create_sem( bufcount - 1, "OpenSound out buffer free" );
|
||||||
|
|
||||||
|
// if ( fBufferAvailableSem < B_OK ) {
|
||||||
|
// return B_ERROR;
|
||||||
|
// }
|
||||||
|
|
||||||
|
input->fThread = spawn_thread(_engine_play_thread_, "OpenSound audio output", B_REAL_TIME_PRIORITY, input);
|
||||||
|
|
||||||
|
if (input->fThread < B_OK) {
|
||||||
|
// delete_sem( fBufferAvailableSem );
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
resume_thread(input->fThread);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t
|
||||||
|
OpenSoundNode::StopPlayThread(node_input *input)
|
||||||
|
{
|
||||||
|
thread_id th;
|
||||||
|
status_t ret;
|
||||||
|
CALLED();
|
||||||
|
{
|
||||||
|
BAutolock L(fDevice->Locker());
|
||||||
|
th = input->fThread;
|
||||||
|
input->fThread = -1;
|
||||||
|
//kill(th, SIGUSR1);
|
||||||
|
}
|
||||||
|
wait_for_thread(th, &ret);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t
|
||||||
|
OpenSoundNode::StartRecThread(node_output *output)
|
||||||
|
{
|
||||||
|
CALLED();
|
||||||
|
// the thread is already started ?
|
||||||
|
if (output->fThread > B_OK)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
//allocate buffer free semaphore
|
||||||
|
// int bufcount = MAX(fDevice->fFragments.fragstotal, 2);//XXX
|
||||||
|
|
||||||
|
// fBufferAvailableSem = create_sem( fDevice->MBL.return_playback_buffers - 1, "multi_audio out buffer free" );
|
||||||
|
// fBufferAvailableSem = create_sem( bufcount - 1, "OpenSound out buffer free" );
|
||||||
|
|
||||||
|
// if ( fBufferAvailableSem < B_OK ) {
|
||||||
|
// return B_ERROR;
|
||||||
|
// }
|
||||||
|
|
||||||
|
output->fThread = spawn_thread(_engine_rec_thread_, "OpenSound audio input", B_REAL_TIME_PRIORITY, output);
|
||||||
|
|
||||||
|
if (output->fThread < B_OK) {
|
||||||
|
//delete_sem( fBufferAvailableSem );
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
resume_thread(output->fThread);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t
|
||||||
|
OpenSoundNode::StopRecThread(node_output *output)
|
||||||
|
{
|
||||||
|
thread_id th = output->fThread;
|
||||||
|
status_t ret;
|
||||||
|
output->fThread = -1;
|
||||||
|
CALLED();
|
||||||
|
{
|
||||||
|
BAutolock L(fDevice->Locker());
|
||||||
|
//kill(th, SIGUSR1);
|
||||||
|
}
|
||||||
|
wait_for_thread(th, &ret);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
OpenSoundNode::AllocateBuffers(node_output &channel)
|
OpenSoundNode::AllocateBuffers(node_output &channel)
|
||||||
{
|
{
|
||||||
@@ -2593,17 +2916,18 @@ OpenSoundNode::UpdateTimeSource(audio_buf_info *abinfo, node_input &input)
|
|||||||
if(fTimeSourceStarted) {
|
if(fTimeSourceStarted) {
|
||||||
int64 played_frames = engine->PlayedFramesCount();
|
int64 played_frames = engine->PlayedFramesCount();
|
||||||
bigtime_t perf_time = (bigtime_t)(played_frames /
|
bigtime_t perf_time = (bigtime_t)(played_frames /
|
||||||
input.fInput.format.u.raw_audio.frame_rate * 1000000);
|
input.fInput.format.u.raw_audio.frame_rate * 1000000LL);
|
||||||
bigtime_t real_time = engine->PlayedRealTime(); //XXX!
|
bigtime_t real_time = engine->PlayedRealTime(); //XXX!
|
||||||
//MBI.played_real_time;
|
//MBI.played_real_time;
|
||||||
/*PRINT(("TS: frames: last %Ld curr %Ld diff %Ld, time: last %Ld curr %Ld diff %Ld\n",
|
/*
|
||||||
|
PRINT(("TS: frames: last %Ld curr %Ld diff %Ld, time: last %Ld curr %Ld diff %Ld\n",
|
||||||
fOldPlayedFramesCount, played_frames, played_frames - fOldPlayedFramesCount,
|
fOldPlayedFramesCount, played_frames, played_frames - fOldPlayedFramesCount,
|
||||||
fOldPlayedRealTime, real_time, real_time - fOldPlayedRealTime));
|
fOldPlayedRealTime, real_time, real_time - fOldPlayedRealTime));
|
||||||
*/
|
*/
|
||||||
float drift;
|
float drift;
|
||||||
if (real_time - fOldPlayedRealTime)
|
if (real_time - fOldPlayedRealTime)
|
||||||
drift = ((played_frames - fOldPlayedFramesCount)
|
drift = ((played_frames - fOldPlayedFramesCount)
|
||||||
/ input.fInput.format.u.raw_audio.frame_rate * 1000000)
|
/ input.fInput.format.u.raw_audio.frame_rate * 1000000LL)
|
||||||
/ (real_time - fOldPlayedRealTime);
|
/ (real_time - fOldPlayedRealTime);
|
||||||
else
|
else
|
||||||
drift = 1;
|
drift = 1;
|
||||||
@@ -2620,7 +2944,9 @@ OpenSoundNode::UpdateTimeSource(audio_buf_info *abinfo, node_input &input)
|
|||||||
* In theory we should pass it, but it seems to work better if we fake a perfect world...
|
* In theory we should pass it, but it seems to work better if we fake a perfect world...
|
||||||
* Maybe it interferes with OSS's queing.
|
* Maybe it interferes with OSS's queing.
|
||||||
*/
|
*/
|
||||||
|
#ifdef DISABLE_DRIFT
|
||||||
drift = 1;
|
drift = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
PublishTime(perf_time, real_time, drift);
|
PublishTime(perf_time, real_time, drift);
|
||||||
|
|
||||||
@@ -2837,13 +3163,40 @@ OpenSoundNode::FindInput(int32 destinationId)
|
|||||||
|
|
||||||
// static:
|
// static:
|
||||||
|
|
||||||
|
|
||||||
int32
|
int32
|
||||||
OpenSoundNode::_run_thread_( void *data )
|
OpenSoundNode::_run_thread_( void *data )
|
||||||
{
|
{
|
||||||
CALLED();
|
CALLED();
|
||||||
|
#if 0
|
||||||
return static_cast<OpenSoundNode *>( data )->RunThread();
|
return static_cast<OpenSoundNode *>( data )->RunThread();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
OpenSoundNode::_sig_handler_(int sig)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int32
|
||||||
|
OpenSoundNode::_engine_play_thread_(void *data)
|
||||||
|
{
|
||||||
|
CALLED();
|
||||||
|
node_input *channel = static_cast<node_input *>(data);
|
||||||
|
return channel->fNode->EnginePlayThread(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
OpenSoundNode::_engine_rec_thread_(void *data)
|
||||||
|
{
|
||||||
|
CALLED();
|
||||||
|
node_output *channel = static_cast<node_output *>(data);
|
||||||
|
return channel->fNode->EngineRecThread(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void OpenSoundNode::GetFlavor(flavor_info * outInfo, int32 id)
|
void OpenSoundNode::GetFlavor(flavor_info * outInfo, int32 id)
|
||||||
{
|
{
|
||||||
CALLED();
|
CALLED();
|
||||||
|
|||||||
@@ -42,8 +42,9 @@
|
|||||||
#include <ParameterWeb.h>
|
#include <ParameterWeb.h>
|
||||||
#include <TimeSource.h>
|
#include <TimeSource.h>
|
||||||
#include <Controllable.h>
|
#include <Controllable.h>
|
||||||
#include <File.h>
|
|
||||||
#include <Entry.h>
|
#include <Entry.h>
|
||||||
|
#include <File.h>
|
||||||
|
#include <List.h>
|
||||||
//#include "soundcard.h"
|
//#include "soundcard.h"
|
||||||
#include "OpenSoundDevice.h"
|
#include "OpenSoundDevice.h"
|
||||||
#include "OpenSoundDeviceEngine.h"
|
#include "OpenSoundDeviceEngine.h"
|
||||||
@@ -53,13 +54,15 @@
|
|||||||
const media_format & producer_format,
|
const media_format & producer_format,
|
||||||
const media_format & consumer_format);*/
|
const media_format & consumer_format);*/
|
||||||
|
|
||||||
|
class OpenSoundNode;
|
||||||
|
|
||||||
class node_input
|
class node_input
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
node_input(media_input &input, media_format format);
|
node_input(media_input &input, media_format format);
|
||||||
~node_input();
|
~node_input();
|
||||||
|
|
||||||
|
OpenSoundNode *fNode;
|
||||||
int32 fEngineId;
|
int32 fEngineId;
|
||||||
OpenSoundDeviceEngine *fRealEngine; // engine it's connected to. can be a shadow one (!= fEngineId)
|
OpenSoundDeviceEngine *fRealEngine; // engine it's connected to. can be a shadow one (!= fEngineId)
|
||||||
int fAFmt; // AFMT_* for this one
|
int fAFmt; // AFMT_* for this one
|
||||||
@@ -67,9 +70,12 @@ class node_input
|
|||||||
media_input fInput;
|
media_input fInput;
|
||||||
media_format fPreferredFormat;
|
media_format fPreferredFormat;
|
||||||
media_format fFormat;
|
media_format fFormat;
|
||||||
|
|
||||||
|
thread_id fThread;
|
||||||
uint32 fBufferCycle;
|
uint32 fBufferCycle;
|
||||||
// multi_buffer_info fOldMBI;
|
// multi_buffer_info fOldMBI;
|
||||||
BBuffer *fBuffer;
|
// BBuffer *fBuffer;
|
||||||
|
BList fBuffers; // of (BBuffer *)
|
||||||
};
|
};
|
||||||
|
|
||||||
class node_output
|
class node_output
|
||||||
@@ -78,6 +84,7 @@ class node_output
|
|||||||
node_output(media_output &output, media_format format);
|
node_output(media_output &output, media_format format);
|
||||||
~node_output();
|
~node_output();
|
||||||
|
|
||||||
|
OpenSoundNode *fNode;
|
||||||
int32 fEngineId;
|
int32 fEngineId;
|
||||||
OpenSoundDeviceEngine *fRealEngine; // engine it's connected to. can be a shadow one (!= fEngineId)
|
OpenSoundDeviceEngine *fRealEngine; // engine it's connected to. can be a shadow one (!= fEngineId)
|
||||||
int fAFmt; // AFMT_* for this one
|
int fAFmt; // AFMT_* for this one
|
||||||
@@ -86,6 +93,7 @@ class node_output
|
|||||||
media_format fPreferredFormat;
|
media_format fPreferredFormat;
|
||||||
media_format fFormat;
|
media_format fFormat;
|
||||||
|
|
||||||
|
thread_id fThread;
|
||||||
BBufferGroup *fBufferGroup;
|
BBufferGroup *fBufferGroup;
|
||||||
bool fOutputEnabled;
|
bool fOutputEnabled;
|
||||||
uint64 fSamplesSent;
|
uint64 fSamplesSent;
|
||||||
@@ -353,6 +361,16 @@ private:
|
|||||||
status_t StartThread();
|
status_t StartThread();
|
||||||
status_t StopThread();
|
status_t StopThread();
|
||||||
|
|
||||||
|
static void _sig_handler_(int sig);
|
||||||
|
static int32 _engine_play_thread_( void *data );
|
||||||
|
static int32 _engine_rec_thread_( void *data );
|
||||||
|
int32 EnginePlayThread(node_input *input);
|
||||||
|
int32 EngineRecThread(node_output *output);
|
||||||
|
|
||||||
|
status_t StartPlayThread(node_input *input);
|
||||||
|
status_t StopPlayThread(node_input *input);
|
||||||
|
status_t StartRecThread(node_output *output);
|
||||||
|
status_t StopRecThread(node_output *output);
|
||||||
|
|
||||||
void AllocateBuffers(node_output &channel);
|
void AllocateBuffers(node_output &channel);
|
||||||
BBuffer* FillNextBuffer(audio_buf_info *abinfo, node_output &channel);
|
BBuffer* FillNextBuffer(audio_buf_info *abinfo, node_output &channel);
|
||||||
@@ -392,7 +410,7 @@ private:
|
|||||||
|
|
||||||
|
|
||||||
//volatile uint32 fBufferCycle;
|
//volatile uint32 fBufferCycle;
|
||||||
sem_id fBuffer_free;
|
sem_id fBufferAvailableSem;
|
||||||
|
|
||||||
|
|
||||||
thread_id fThread;
|
thread_id fThread;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ Distributed under the terms of the MIT License.
|
|||||||
|
|
||||||
OpenSound System v4.0 drivers (c) 4Front Technologies.
|
OpenSound System v4.0 drivers (c) 4Front Technologies.
|
||||||
Port by François Revol ([email protected])
|
Port by François Revol ([email protected])
|
||||||
Released under GPL. Sources available by mail.
|
Released under BSD licence. Sources available by mail.
|
||||||
|
|
||||||
|
|
||||||
Release and dev notes
|
Release and dev notes
|
||||||
|
|||||||
Reference in New Issue
Block a user