/***************************************************************************** * InterfaceWindow::_SetMenusEnabled *****************************************************************************/ void InterfaceWindow::_SetMenusEnabled(bool hasFile, bool hasChapters, bool hasTitles) { if (!hasFile) { hasChapters = false; hasTitles = false; } if ( LockWithTimeout( INTERFACE_LOCKING_TIMEOUT ) == B_OK) { if ( fNextChapterMI->IsEnabled() != hasChapters ) fNextChapterMI->SetEnabled( hasChapters ); if ( fPrevChapterMI->IsEnabled() != hasChapters ) fPrevChapterMI->SetEnabled( hasChapters ); if ( fChapterMenu->IsEnabled() != hasChapters ) fChapterMenu->SetEnabled( hasChapters ); if ( fNextTitleMI->IsEnabled() != hasTitles ) fNextTitleMI->SetEnabled( hasTitles ); if ( fPrevTitleMI->IsEnabled() != hasTitles ) fPrevTitleMI->SetEnabled( hasTitles ); if ( fTitleMenu->IsEnabled() != hasTitles ) fTitleMenu->SetEnabled( hasTitles ); if ( fAudioMenu->IsEnabled() != hasFile ) fAudioMenu->SetEnabled( hasFile ); if ( fNavigationMenu->IsEnabled() != hasFile ) fNavigationMenu->SetEnabled( hasFile ); if ( fLanguageMenu->IsEnabled() != hasFile ) fLanguageMenu->SetEnabled( hasFile ); if ( fSubtitlesMenu->IsEnabled() != hasFile ) fSubtitlesMenu->SetEnabled( hasFile ); if ( fSpeedMenu->IsEnabled() != hasFile ) fSpeedMenu->SetEnabled( hasFile ); Unlock(); } }
void MixerCore::_MixThread() { // The broken BeOS R5 multiaudio node starts with time 0, // then publishes negative times for about 50ms, publishes 0 // again until it finally reaches time values > 0 if (!LockFromMixThread()) return; bigtime_t start = fTimeSource->Now(); Unlock(); while (start <= 0) { TRACE("MixerCore: delaying _MixThread start, timesource is at %Ld\n", start); snooze(5000); if (!LockFromMixThread()) return; start = fTimeSource->Now(); Unlock(); } if (!LockFromMixThread()) return; bigtime_t latency = max((bigtime_t)3600, bigtime_t(0.4 * buffer_duration( fOutput->MediaOutput().format.u.raw_audio))); // TODO: when the format changes while running, everything is wrong! bigtime_t bufferRequestTimeout = buffer_duration( fOutput->MediaOutput().format.u.raw_audio) / 2; TRACE("MixerCore: starting _MixThread at %Ld with latency %Ld and " "downstream latency %Ld, bufferRequestTimeout %Ld\n", start, latency, fDownstreamLatency, bufferRequestTimeout); // We must read from the input buffer at a position (pos) that is always // a multiple of fMixBufferFrameCount. int64 temp = frames_for_duration(fMixBufferFrameRate, start); int64 frameBase = ((temp / fMixBufferFrameCount) + 1) * fMixBufferFrameCount; bigtime_t timeBase = duration_for_frames(fMixBufferFrameRate, frameBase); Unlock(); TRACE("MixerCore: starting _MixThread, start %Ld, timeBase %Ld, " "frameBase %Ld\n", start, timeBase, frameBase); ASSERT(fMixBufferFrameCount > 0); #if DEBUG uint64 bufferIndex = 0; #endif typedef RtList<chan_info> chan_info_list; chan_info_list inputChanInfos[MAX_CHANNEL_TYPES]; BStackOrHeapArray<chan_info_list, 16> mixChanInfos(fMixBufferChannelCount); // TODO: this does not support changing output channel count bigtime_t eventTime = timeBase; int64 framePos = 0; for (;;) { if (!LockFromMixThread()) return; bigtime_t waitUntil = fTimeSource->RealTimeFor(eventTime, 0) - latency - fDownstreamLatency; Unlock(); status_t rv = acquire_sem_etc(fMixThreadWaitSem, 1, B_ABSOLUTE_TIMEOUT, waitUntil); if (rv == B_INTERRUPTED) continue; if (rv != B_TIMED_OUT && rv < B_OK) return; if (!LockWithTimeout(10000)) { ERROR("MixerCore: LockWithTimeout failed\n"); continue; } // no inputs or output muted, skip further processing and just send an // empty buffer if (fInputs->IsEmpty() || fOutput->IsMuted()) { int size = fOutput->MediaOutput().format.u.raw_audio.buffer_size; BBuffer* buffer = fBufferGroup->RequestBuffer(size, bufferRequestTimeout); if (buffer != NULL) { memset(buffer->Data(), 0, size); // fill in the buffer header media_header* hdr = buffer->Header(); hdr->type = B_MEDIA_RAW_AUDIO; hdr->size_used = size; hdr->time_source = fTimeSource->ID(); hdr->start_time = eventTime; if (fNode->SendBuffer(buffer, fOutput) != B_OK) { #if DEBUG ERROR("MixerCore: SendBuffer failed for buffer %Ld\n", bufferIndex); #else ERROR("MixerCore: SendBuffer failed\n"); #endif buffer->Recycle(); } } else { #if DEBUG ERROR("MixerCore: RequestBuffer failed for buffer %Ld\n", bufferIndex); #else ERROR("MixerCore: RequestBuffer failed\n"); #endif } goto schedule_next_event; } int64 currentFramePos; currentFramePos = frameBase + framePos; // mix all data from all inputs into the mix buffer ASSERT(currentFramePos % fMixBufferFrameCount == 0); PRINT(4, "create new buffer event at %Ld, reading input frames at " "%Ld\n", eventTime, currentFramePos); // Init the channel information for each MixerInput. for (int i = 0; MixerInput* input = Input(i); i++) { int count = input->GetMixerChannelCount(); for (int channel = 0; channel < count; channel++) { int type; const float* base; uint32 sampleOffset; float gain; if (!input->GetMixerChannelInfo(channel, currentFramePos, eventTime, &base, &sampleOffset, &type, &gain)) { continue; } if (type < 0 || type >= MAX_CHANNEL_TYPES) continue; chan_info* info = inputChanInfos[type].Create(); info->base = (const char*)base; info->sample_offset = sampleOffset; info->gain = gain; } } for (int channel = 0; channel < fMixBufferChannelCount; channel++) { int sourceCount = fOutput->GetOutputChannelSourceCount(channel); for (int i = 0; i < sourceCount; i++) { int type; float gain; fOutput->GetOutputChannelSourceInfoAt(channel, i, &type, &gain); if (type < 0 || type >= MAX_CHANNEL_TYPES) continue; int count = inputChanInfos[type].CountItems(); for (int j = 0; j < count; j++) { chan_info* info = inputChanInfos[type].ItemAt(j); chan_info* newInfo = mixChanInfos[channel].Create(); newInfo->base = info->base; newInfo->sample_offset = info->sample_offset; newInfo->gain = info->gain * gain; } } } memset(fMixBuffer, 0, fMixBufferChannelCount * fMixBufferFrameCount * sizeof(float)); for (int channel = 0; channel < fMixBufferChannelCount; channel++) { PRINT(5, "_MixThread: channel %d has %d sources\n", channel, mixChanInfos[channel].CountItems()); int count = mixChanInfos[channel].CountItems(); for (int i = 0; i < count; i++) { chan_info* info = mixChanInfos[channel].ItemAt(i); PRINT(5, "_MixThread: base %p, sample-offset %2d, gain %.3f\n", info->base, info->sample_offset, info->gain); // This looks slightly ugly, but the current GCC will generate // the fastest code this way. // fMixBufferFrameCount is always > 0. uint32 dstSampleOffset = fMixBufferChannelCount * sizeof(float); uint32 srcSampleOffset = info->sample_offset; register char* dst = (char*)&fMixBuffer[channel]; register char* src = (char*)info->base; register float gain = info->gain; register int j = fMixBufferFrameCount; do { *(float*)dst += *(const float*)src * gain; dst += dstSampleOffset; src += srcSampleOffset; } while (--j); } } // request a buffer BBuffer* buffer; buffer = fBufferGroup->RequestBuffer( fOutput->MediaOutput().format.u.raw_audio.buffer_size, bufferRequestTimeout); if (buffer != NULL) { // copy data from mix buffer into output buffer for (int i = 0; i < fMixBufferChannelCount; i++) { fResampler[i]->Resample( reinterpret_cast<char*>(fMixBuffer) + i * sizeof(float), fMixBufferChannelCount * sizeof(float), fMixBufferFrameCount, reinterpret_cast<char*>(buffer->Data()) + (i * bytes_per_sample( fOutput->MediaOutput().format.u.raw_audio)), bytes_per_frame(fOutput->MediaOutput().format.u.raw_audio), frames_per_buffer( fOutput->MediaOutput().format.u.raw_audio), fOutputGain * fOutput->GetOutputChannelGain(i)); } PRINT(4, "send buffer, inframes %ld, outframes %ld\n", fMixBufferFrameCount, frames_per_buffer(fOutput->MediaOutput().format.u.raw_audio)); // fill in the buffer header media_header* hdr = buffer->Header(); hdr->type = B_MEDIA_RAW_AUDIO; hdr->size_used = fOutput->MediaOutput().format.u.raw_audio.buffer_size; hdr->time_source = fTimeSource->ID(); hdr->start_time = eventTime; // swap byte order if necessary fOutput->AdjustByteOrder(buffer); // send the buffer status_t res = fNode->SendBuffer(buffer, fOutput); if (res != B_OK) { #if DEBUG ERROR("MixerCore: SendBuffer failed for buffer %Ld\n", bufferIndex); #else ERROR("MixerCore: SendBuffer failed\n"); #endif buffer->Recycle(); } } else { #if DEBUG ERROR("MixerCore: RequestBuffer failed for buffer %Ld\n", bufferIndex); #else ERROR("MixerCore: RequestBuffer failed\n"); #endif } // make all lists empty for (int i = 0; i < MAX_CHANNEL_TYPES; i++) inputChanInfos[i].MakeEmpty(); for (int i = 0; i < fOutput->GetOutputChannelCount(); i++) mixChanInfos[i].MakeEmpty(); schedule_next_event: // schedule next event framePos += fMixBufferFrameCount; eventTime = timeBase + bigtime_t((1000000LL * framePos) / fMixBufferFrameRate); Unlock(); #if DEBUG bufferIndex++; #endif } }
/***************************************************************************** * InterfaceWindow::UpdateInterface *****************************************************************************/ void InterfaceWindow::UpdateInterface() { if( !p_input ) { p_input = (input_thread_t *) vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE ); } else if( p_input->b_dead ) { vlc_object_release( p_input ); p_input = NULL; } /* Get ready to update the interface */ if( LockWithTimeout( INTERFACE_LOCKING_TIMEOUT ) != B_OK ) { return; } if( b_playlist_update ) { #if 0 if( fPlaylistWindow->Lock() ) { fPlaylistWindow->UpdatePlaylist( true ); fPlaylistWindow->Unlock(); b_playlist_update = false; } #endif p_mediaControl->SetEnabled( !playlist_IsEmpty( p_playlist ) ); } if( p_input ) { vlc_value_t val; p_mediaControl->SetEnabled( true ); bool hasTitles = !var_Get( p_input, "title", &val ); bool hasChapters = !var_Get( p_input, "chapter", &val ); p_mediaControl->SetStatus( var_GetInteger( p_input, "state" ), var_GetInteger( p_input, "rate" ) ); var_Get( p_input, "position", &val ); p_mediaControl->SetProgress( val.f_float ); _SetMenusEnabled( true, hasChapters, hasTitles ); _UpdateSpeedMenu( var_GetInteger( p_input, "rate" ) ); // enable/disable skip buttons #if 0 bool canSkipPrev; bool canSkipNext; p_wrapper->GetNavCapabilities( &canSkipPrev, &canSkipNext ); p_mediaControl->SetSkippable( canSkipPrev, canSkipNext ); #endif audio_volume_t i_volume; aout_VolumeGet( p_intf, &i_volume ); p_mediaControl->SetAudioEnabled( true ); p_mediaControl->SetMuted( i_volume ); } else { p_mediaControl->SetAudioEnabled( false ); _SetMenusEnabled( false ); if( !playlist_IsEmpty( p_playlist ) ) { p_mediaControl->SetProgress( 0 ); #if 0 // enable/disable skip buttons bool canSkipPrev; bool canSkipNext; p_wrapper->GetNavCapabilities( &canSkipPrev, &canSkipNext ); p_mediaControl->SetSkippable( canSkipPrev, canSkipNext ); #endif } else { p_mediaControl->SetEnabled( false ); } } Unlock(); fLastUpdateTime = system_time(); }
bool EMessageQueue::Lock() { return(LockWithTimeout(E_INFINITE_TIMEOUT) == E_OK); }