Index: src/add-ons/media/media-add-ons/opensound/OpenSoundDevice.h =================================================================== --- src/add-ons/media/media-add-ons/opensound/OpenSoundDevice.h (revision 25209) +++ src/add-ons/media/media-add-ons/opensound/OpenSoundDevice.h (working copy) @@ -33,6 +33,13 @@ #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 */ /* also used to mark the raw_audio node input&outputs */ //XXX: _OE ? Index: src/add-ons/media/media-add-ons/opensound/OpenSoundDeviceEngine.cpp =================================================================== --- src/add-ons/media/media-add-ons/opensound/OpenSoundDeviceEngine.cpp (revision 25209) +++ src/add-ons/media/media-add-ons/opensound/OpenSoundDeviceEngine.cpp (working copy) @@ -307,6 +307,108 @@ } +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) { //CALLED(); @@ -340,6 +442,12 @@ int64 OpenSoundDeviceEngine::PlayedFramesCount(void) { + int64 played; + int32 fifoed; + played = GetCurrentOPtr(&fifoed); + //played += fifoed; + //return played; + fPlayedFramesCount = played; return fPlayedFramesCount;//XXX return fPlayedFramesCount - (GetODelay() / (fMediaFormat.u.raw_audio.channel_count * (fMediaFormat.AudioFormat() & media_raw_audio_format::B_AUDIO_SIZE_MASK))); @@ -443,8 +551,10 @@ { status_t err; int afmt = 0; + char buf[1024]; CALLED(); fmt &= rec ? Info()->iformats : Info()->oformats; + if (fmt == 0) return B_MEDIA_BAD_FORMAT; media_format wc; @@ -540,12 +650,12 @@ raw.buffer_size = DEFAULT_BUFFER_SIZE; } else { + PRINT(("%s: unknown media type\n", __FUNCTION__)); Close(); return EINVAL; } // cache it fMediaFormat = format; - char buf[1024]; string_for_format(format, buf, 1024); PRINT(("%s: %s\n", __FUNCTION__, buf)); return B_OK; @@ -676,3 +786,4 @@ PRINT(("%s: %s\n", __FUNCTION__, buf)); return B_OK; } + Index: src/add-ons/media/media-add-ons/opensound/OpenSoundNode.cpp =================================================================== --- src/add-ons/media/media-add-ons/opensound/OpenSoundNode.cpp (revision 25209) +++ src/add-ons/media/media-add-ons/opensound/OpenSoundNode.cpp (working copy) @@ -44,12 +44,13 @@ #include #include #include -#include #include #include #include #include #include +#include +#include #include "OpenSoundNode.h" #include "driver_io.h" @@ -73,6 +74,7 @@ node_input::node_input(media_input &input, media_format format) { CALLED(); + fNode = NULL; fEngineId = -1; fRealEngine = NULL; fAFmt = 0; @@ -80,6 +82,7 @@ fPreferredFormat = format; fBufferCycle = 1; fBuffer = NULL; + fThread = -1; } node_input::~node_input() @@ -92,12 +95,14 @@ fOutputEnabled(true) { CALLED(); + fNode = NULL; fEngineId = -1; fRealEngine = NULL; fAFmt = 0; fOutput = output; fPreferredFormat = format; fBufferCycle = 1; + fThread = -1; } node_output::~node_output() @@ -115,7 +120,7 @@ CALLED(); fAddOn->GetConfigurationFor(this, NULL); - StopThread(); + //StopThread(); BMediaEventLooper::Quit(); fWeb = NULL; @@ -283,6 +288,7 @@ currentInput->fChannelId = i;//XXX:REMOVEME fDevice->MD.channels[i].channel_id; currentInput->fEngineId = i; currentInput->fAFmt = fmt; + currentInput->fNode = this; fInputs.AddItem(currentInput); currentInput->fInput.format.u.raw_audio.format = media_raw_audio_format::wildcard.format; @@ -332,6 +338,7 @@ currentOutput->fChannelId = i;//XXX:REMOVEME fDevice->MD.channels[i].channel_id; currentOutput->fEngineId = i; currentOutput->fAFmt = fmt; + currentOutput->fNode = this; fOutputs.AddItem(currentOutput); } } @@ -553,11 +560,14 @@ node_input *channel = FindInput(for_whom); - if(channel==NULL) { + if(channel==NULL || channel->fRealEngine==NULL) { fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); 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 + //PRINT(("############ OpenSoundNode::%s: EventLatency %Ld, OSS %d\n", __FUNCTION__, EventLatency(), channel->fRealEngine->Latency())); + //*out_latency += MIN_SNOOZING; *out_timesource = TimeSource()->ID(); return B_OK; } @@ -599,7 +609,8 @@ *out_input = channel->fInput; // we are sure the thread is started - StartThread(); + //StartThread(); + StartPlayThread(channel); return B_OK; } @@ -619,7 +630,8 @@ fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); return; } - + + StopPlayThread(channel); channel->fInput.source = media_source::null; channel->fInput.format = channel->fPreferredFormat; if (channel->fRealEngine) @@ -942,7 +954,8 @@ engine->StartRecording(); // we are sure the thread is started - StartThread(); + //StartThread(); + StartRecThread(channel); } void @@ -959,6 +972,8 @@ return; } + StopRecThread(channel); + BAutolock L(fDevice->Locker()); OpenSoundDeviceEngine *engine = channel->fRealEngine; @@ -1129,25 +1144,32 @@ // who sent it to us if ((RunMode() != B_OFFLINE) && // lateness doesn't matter in offline mode... (RunMode() != B_RECORDING) && // ...or in recording mode - (how_early < 0LL)) + (how_early < 0LL) && false /* XXX:DEBUG */) { //mLateBuffers++; NotifyLateProducer(channel->fInput.source, -how_early, perf_time); fprintf(stderr," <- LATE BUFFER : %lli\n", how_early); buffer->Recycle(); + release_sem(fBufferAvailableSem); } else { //WriteBuffer(buffer, *channel); - if(channel->fBuffer != NULL) { + if (channel->fBuffer != NULL) { PRINT(("OpenSoundNode::HandleBuffer snoozing recycling channelId : %i, how_early:%lli\n", channel->fChannelId, how_early)); //channel->fBuffer->Recycle(); + release_sem(fBufferAvailableSem); snooze(100); - if(channel->fBuffer != NULL) + if(channel->fBuffer != NULL) { + PRINT(("OpenSoundNode::HandleBuffer old buffer still there, recycling\n")); buffer->Recycle(); - else + //release_sem(fBufferAvailableSem); + } else { channel->fBuffer = buffer; + release_sem(fBufferAvailableSem); + } } else { //PRINT(("OpenSoundNode::HandleBuffer writing channelId : %i, how_early:%lli\n", channel->fChannelId, how_early)); channel->fBuffer = buffer; + release_sem(fBufferAvailableSem); } } return B_OK; @@ -1247,7 +1269,7 @@ PRINT(("TimeSourceOp op B_TIMESOURCE_START\n")); if (RunState() != BMediaEventLooper::B_STARTED) { fTimeSourceStarted = true; - StartThread(); + //StartThread(); media_timed_event startEvent(0, BTimedEventQueue::B_START); EventQueue()->AddEvent(startEvent); @@ -1259,7 +1281,7 @@ media_timed_event stopEvent(0, BTimedEventQueue::B_STOP); EventQueue()->AddEvent(stopEvent); fTimeSourceStarted = false; - StopThread(); + //StopThread(); PublishTime(0, 0, 0); } break; @@ -1269,7 +1291,7 @@ media_timed_event stopEvent(0, BTimedEventQueue::B_STOP); EventQueue()->AddEvent(stopEvent); fTimeSourceStarted = false; - StopThread(); + //StopThread(); PublishTime(0, 0, 0); } break; @@ -2048,15 +2070,38 @@ OpenSoundNode::RunThread() { int32 i; + int32 bufferAvailReq = 1; + bigtime_t timeout = MIN_SNOOZING; CALLED(); + //set_thread_priority(find_thread(NULL), 5);//XXX:DEBUG + + return 0; //XXX: REMOVE + while ( 1 ) { + status_t err; + bigtime_t before = system_time(); // 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 - 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; } + 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())); @@ -2082,7 +2127,8 @@ if (avail < 1) continue; -#if 0 +//engine->GetOUnderruns(); +#if 1 // update the timesource if(input->fChannelId==0) { //PRINT(("updating timesource\n")); @@ -2093,21 +2139,39 @@ if(input->fBuffer!=NULL) { if (avail < input->fBuffer->SizeUsed()) 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); input->fBuffer->Recycle(); input->fBuffer = NULL; + bufferAvailReq++; } else { if (avail < abinfo.fragsize) continue; //XXX: write silence // write a nulled fragment + PRINT(("OpenSoundNode::RunThread: input[%d]: sending zeros\n", i)); +//#ifdef WRITE_ZEROS if(input->fInput.source != media_source::null) WriteZeros(*input, abinfo.fragsize); +//#endif } -#if 1 +#if 0 // update the timesource if(input->fChannelId==0) { //PRINT(("updating timesource\n")); @@ -2164,8 +2228,8 @@ fDevice->Locker()->Unlock(); //XXX - snooze(5000); - release_sem(fBuffer_free);//XXX + //snooze(1000); + //release_sem(fBufferAvailableSem);//XXX } #if MA multi_buffer_info MBI;//, oldMBI; @@ -2175,7 +2239,7 @@ while ( 1 ) { //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; } @@ -2227,7 +2291,7 @@ } //mark buffer free - release_sem( fBuffer_free ); + release_sem( fBufferAvailableSem ); } else { //PRINT(("playback_buffer_cycle non ok input : %i\n", i)); } @@ -2275,6 +2339,153 @@ return B_OK; } + +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 + BBuffer *buffer = input->fBuffer; + input->fBuffer = NULL; + + 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 OpenSoundNode::WriteZeros(node_input &input, size_t len) { @@ -2542,17 +2753,17 @@ //allocate buffer free semaphore int bufcount = MAX(fDevice->fFragments.fragstotal, 2);//XXX -// fBuffer_free = 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( fDevice->MBL.return_playback_buffers - 1, "multi_audio out buffer free" ); + fBufferAvailableSem = create_sem( bufcount - 1, "OpenSound out buffer free" ); - if ( fBuffer_free < B_OK ) { + if ( fBufferAvailableSem < B_OK ) { return B_ERROR; } fThread = spawn_thread( _run_thread_, "OpenSound audio output", B_REAL_TIME_PRIORITY, this ); if ( fThread < B_OK ) { - delete_sem( fBuffer_free ); + delete_sem( fBufferAvailableSem ); return B_ERROR; } @@ -2564,11 +2775,101 @@ OpenSoundNode::StopThread() { CALLED(); - delete_sem( fBuffer_free ); + delete_sem( fBufferAvailableSem ); wait_for_thread( fThread, &fThread ); 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 OpenSoundNode::AllocateBuffers(node_output &channel) { @@ -2593,17 +2894,18 @@ if(fTimeSourceStarted) { int64 played_frames = engine->PlayedFramesCount(); 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! //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, fOldPlayedRealTime, real_time, real_time - fOldPlayedRealTime)); */ float drift; if (real_time - fOldPlayedRealTime) 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); else drift = 1; @@ -2620,7 +2922,9 @@ * 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. */ +#ifdef DISABLE_DRIFT drift = 1; +#endif PublishTime(perf_time, real_time, drift); @@ -2837,6 +3141,7 @@ // static: + int32 OpenSoundNode::_run_thread_( void *data ) { @@ -2844,6 +3149,30 @@ return static_cast( data )->RunThread(); } + +void +OpenSoundNode::_sig_handler_(int sig) +{ +} + +int32 +OpenSoundNode::_engine_play_thread_(void *data) +{ + CALLED(); + node_input *channel = static_cast(data); + return channel->fNode->EnginePlayThread(channel); +} + + +int32 +OpenSoundNode::_engine_rec_thread_(void *data) +{ + CALLED(); + node_output *channel = static_cast(data); + return channel->fNode->EngineRecThread(channel); +} + + void OpenSoundNode::GetFlavor(flavor_info * outInfo, int32 id) { CALLED(); Index: src/add-ons/media/media-add-ons/opensound/OpenSound_README.txt =================================================================== --- src/add-ons/media/media-add-ons/opensound/OpenSound_README.txt (revision 25209) +++ src/add-ons/media/media-add-ons/opensound/OpenSound_README.txt (working copy) @@ -5,7 +5,7 @@ OpenSound System v4.0 drivers (c) 4Front Technologies. Port by François Revol (revol@free.fr) -Released under GPL. Sources available by mail. +Released under BSD licence. Sources available by mail. Release and dev notes Index: src/add-ons/media/media-add-ons/opensound/OpenSoundDeviceEngine.h =================================================================== --- src/add-ons/media/media-add-ons/opensound/OpenSoundDeviceEngine.h (revision 25209) +++ src/add-ons/media/media-add-ons/opensound/OpenSoundDeviceEngine.h (working copy) @@ -38,7 +38,7 @@ status_t UpdateInfo(); // shortcuts int Caps() const { return fAudioInfo.caps; }; - int Latency() const { return fAudioInfo.latency; }; + int Latency() const { return (fAudioInfo.latency<0) ? 0 : fAudioInfo.latency; }; int GetChannels(void); @@ -55,10 +55,16 @@ size_t GetISpace(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); status_t StartRecording(void); - + int64 PlayedFramesCount(void); bigtime_t PlayedRealTime(void); Index: src/add-ons/media/media-add-ons/opensound/OpenSoundNode.h =================================================================== --- src/add-ons/media/media-add-ons/opensound/OpenSoundNode.h (revision 25209) +++ src/add-ons/media/media-add-ons/opensound/OpenSoundNode.h (working copy) @@ -53,13 +53,15 @@ const media_format & producer_format, const media_format & consumer_format);*/ - +class OpenSoundNode; + class node_input { public: node_input(media_input &input, media_format format); ~node_input(); + OpenSoundNode *fNode; int32 fEngineId; OpenSoundDeviceEngine *fRealEngine; // engine it's connected to. can be a shadow one (!= fEngineId) int fAFmt; // AFMT_* for this one @@ -67,6 +69,8 @@ media_input fInput; media_format fPreferredFormat; media_format fFormat; + + thread_id fThread; uint32 fBufferCycle; // multi_buffer_info fOldMBI; BBuffer *fBuffer; @@ -78,6 +82,7 @@ node_output(media_output &output, media_format format); ~node_output(); + OpenSoundNode *fNode; int32 fEngineId; OpenSoundDeviceEngine *fRealEngine; // engine it's connected to. can be a shadow one (!= fEngineId) int fAFmt; // AFMT_* for this one @@ -86,6 +91,7 @@ media_format fPreferredFormat; media_format fFormat; + thread_id fThread; BBufferGroup *fBufferGroup; bool fOutputEnabled; uint64 fSamplesSent; @@ -353,6 +359,16 @@ status_t StartThread(); 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); BBuffer* FillNextBuffer(audio_buf_info *abinfo, node_output &channel); @@ -392,7 +408,7 @@ //volatile uint32 fBufferCycle; - sem_id fBuffer_free; + sem_id fBufferAvailableSem; thread_id fThread;