Пример #1
0
    void AudioRenderer::SetClock(IReferenceClock* pClock)
    {
        CAutoLock objectLock(this);

        m_graphClock = pClock;

        if (m_graphClock && !IsEqualObject(m_graphClock, m_myClock.GetOwner()))
        {
            if (!m_externalClock)
                ClearDevice();

            m_externalClock = true;
        }
        else
        {
            if (m_externalClock)
                ClearDevice();

            m_externalClock = false;
        }
    }
Пример #2
0
    void AudioRenderer::CreateDevice()
    {
        CAutoLock objectLock(this);

        assert(!m_device);
        assert(m_inputFormat);

        m_deviceSettingsSerial = m_settings->GetSerial();
        m_defaultDeviceSerial = m_deviceManager.GetDefaultDeviceSerial();
        m_device = m_deviceManager.CreateDevice(m_inputFormat, m_live || m_externalClock, m_settings);

        if (m_device)
        {
            m_sampleCorrection.NewDeviceBuffer();

            InitializeProcessors();

            m_startClockOffset = m_sampleCorrection.GetLastFrameEnd();

            if (m_state == State_Running)
                StartDevice();
        }
    }
Пример #3
0
    void AudioRenderer::InitializeProcessors()
    {
        CAutoLock objectLock(this);
        assert(m_inputFormat);
        assert(m_device);

        if (m_device->IsBitstream())
            return;

        const auto inRate = m_inputFormat->nSamplesPerSec;
        const auto inChannels = m_inputFormat->nChannels;
        const auto inMask = DspMatrix::GetChannelMask(*m_inputFormat);
        const auto outRate = m_device->GetWaveFormat()->nSamplesPerSec;
        const auto outChannels = m_device->GetWaveFormat()->nChannels;
        const auto outMask = DspMatrix::GetChannelMask(*m_device->GetWaveFormat());

        m_dspMatrix.Initialize(inChannels, inMask, outChannels, outMask);
        m_dspRate.Initialize(m_live || m_externalClock, inRate, outRate, outChannels);
        m_dspRealtimeRate.Initialize(m_live || m_externalClock, inRate, outRate, outChannels);
        m_dspTempo.Initialize(m_rate, outRate, outChannels);
        m_dspCrossfeed.Initialize(m_settings, outRate, outChannels, outMask);
        m_dspLimiter.Initialize(outRate, outChannels, m_device->IsExclusive());
        m_dspDither.Initialize(m_device->GetDspFormat());
    }
Пример #4
0
void detachThread(Thread *thread) {
    Object *group, *excep;
    //ExecEnv *ee = thread->ee;
    //Object *jThread = ee->thread;
    Object *jThread = thread->thread;
    Object *vmthread = (Object*)INST_DATA(jThread)[vmthread_offset];

    /* Get the thread's group */
    group = (Object *)INST_DATA(jThread)[group_offset];

    /* If there's an uncaught exception, call uncaughtException on the thread's
       exception handler, or the thread's group if this is unset */
    if((excep = exceptionOccurred())) {
        FieldBlock *fb = findField(thread_class, SYMBOL(exceptionHandler),
                                                 SYMBOL(sig_java_lang_Thread_UncaughtExceptionHandler));
        Object *thread_handler = fb == NULL ? NULL : (Object *)INST_DATA(jThread)[fb->offset];
        Object *handler = thread_handler == NULL ? group : thread_handler;

        MethodBlock *uncaught_exp = lookupMethod(handler->classobj, SYMBOL(uncaughtException),
                                                 SYMBOL(_java_lang_Thread_java_lang_Throwable__V));

        if(uncaught_exp) {
            clearException();
            DummyFrame dummy;
            executeMethod(&dummy, handler, uncaught_exp, jThread, excep);
        } else
            printException();
    }

    /* remove thread from thread group */
    DummyFrame dummy;
    executeMethod(&dummy, group, (CLASS_CB(group->classobj))->method_table[rmveThrd_mtbl_idx], jThread);

    /* set VMThread ref in Thread object to null - operations after this
       point will result in an IllegalThreadStateException */
    INST_DATA(jThread)[vmthread_offset] = 0;

    /* Remove thread from the ID map hash table */
    deleteThreadFromHash(thread);

    /* Disable suspend to protect lock operation */
    disableSuspend(thread);

    /* Grab global lock, and update thread structures protected by
       it (thread list, thread ID and number of daemon threads) */
    pthread_mutex_lock(&lock);

    /* remove from thread list... */
    if((thread->prev->next = thread->next))
        thread->next->prev = thread->prev;

    /* One less live thread */
    threads_count--;

    /* Recycle the thread's thread ID */
    freeThreadID(thread->id);

    /* Handle daemon thread status */
    if(!INST_DATA(jThread)[daemon_offset])
        non_daemon_thrds--;

    pthread_mutex_unlock(&lock);

    /* notify any threads waiting on VMThread object -
       these are joining this thread */
    objectLock(vmthread);
    objectNotifyAll(vmthread);
    objectUnlock(vmthread);

    /* It is safe to free the thread's ExecEnv and stack now as these are
       only used within the thread.  It is _not_ safe to free the native
       thread structure as another thread may be concurrently accessing it.
       However, they must have a reference to the VMThread -- therefore, it
       is safe to free during GC when the VMThread is determined to be no
       longer reachable. */
//    sysFree(ee->stack);
    //sysFree(ee);

    /* If no more daemon threads notify the main thread (which
       may be waiting to exit VM).  Note, this is not protected
       by lock, but main thread checks again */

    if(non_daemon_thrds == 0) {
        /* No need to bother with disabling suspension
         * around lock, as we're no longer on thread list */
        pthread_mutex_lock(&exit_lock);
        pthread_cond_signal(&exit_cv);
        pthread_mutex_unlock(&exit_lock);
    }

    TRACE("Thread 0x%x id: %d detached from VM\n", thread, thread->id);
}
Пример #5
0
    bool AudioRenderer::IsLive()
    {
        CAutoLock objectLock(this);

        return m_live;
    }
Пример #6
0
    bool AudioRenderer::OnExternalClock()
    {
        CAutoLock objectLock(this);

        return m_externalClock;
    }
Пример #7
0
    void AudioRenderer::ApplyRateCorrection(DspChunk& chunk)
    {
        CAutoLock objectLock(this);
        assert(m_device);
        assert(!m_device->IsBitstream());
        assert(m_state == State_Running);

        if (chunk.IsEmpty())
            return;

        const REFERENCE_TIME latency = llMulDiv(chunk.GetFrameCount(), OneSecond, chunk.GetRate(), 0) +
                                       m_device->GetStreamLatency() + OneMillisecond * 10;

        const REFERENCE_TIME remaining = m_device->GetEnd() - m_device->GetPosition();

        REFERENCE_TIME deltaTime = 0;

        if (m_live)
        {
            // Rate matching.
            if (remaining > latency)
            {
                size_t dropFrames = (size_t)llMulDiv(m_device->GetWaveFormat()->nSamplesPerSec,
                                                     remaining - latency, OneSecond, 0);

                dropFrames = std::min(dropFrames, chunk.GetFrameCount());

                chunk.ShrinkHead(chunk.GetFrameCount() - dropFrames);

                DebugOut("AudioRenderer drop", dropFrames, "frames for rate matching");
            }
        }
        else
        {
            // Clock matching.
            assert(m_externalClock);

            REFERENCE_TIME graphTime, myTime, myStartTime;
            if (SUCCEEDED(m_myClock.GetAudioClockStartTime(&myStartTime)) &&
                SUCCEEDED(m_myClock.GetAudioClockTime(&myTime, nullptr)) &&
                SUCCEEDED(m_graphClock->GetTime(&graphTime)) &&
                myTime > myStartTime)
            {
                myTime -= m_device->GetSilence();

                if (myTime > graphTime)
                {
                    // Pad and adjust backwards.
                    REFERENCE_TIME padTime = myTime - graphTime;
                    assert(padTime >= 0);

                    size_t padFrames = (size_t)llMulDiv(m_device->GetWaveFormat()->nSamplesPerSec,
                                                        padTime, OneSecond, 0);

                    if (padFrames > m_device->GetWaveFormat()->nSamplesPerSec / 33) // ~30ms threshold
                    {
                        DspChunk tempChunk(chunk.GetFormat(), chunk.GetChannelCount(),
                                           chunk.GetFrameCount() + padFrames, chunk.GetRate());

                        size_t padBytes = tempChunk.GetFrameSize() * padFrames;
                        ZeroMemory(tempChunk.GetData(), padBytes);
                        memcpy(tempChunk.GetData() + padBytes, chunk.GetData(), chunk.GetSize());

                        chunk = std::move(tempChunk);

                        REFERENCE_TIME paddedTime = llMulDiv(padFrames, OneSecond,
                                                             m_device->GetWaveFormat()->nSamplesPerSec, 0);

                        m_myClock.OffsetSlavedClock(-paddedTime);
                        padTime -= paddedTime;
                        assert(padTime >= 0);

                        DebugOut("AudioRenderer pad", paddedTime / 10000., "ms for clock matching at",
                                 m_sampleCorrection.GetLastFrameEnd() / 10000., "frame position");
                    }

                    // Correct the rest with variable rate.
                    m_dspRealtimeRate.Adjust(padTime);
                    m_myClock.OffsetSlavedClock(-padTime);
                }
                else if (remaining > latency)
                {
                    // Crop and adjust forwards.
                    assert(myTime <= graphTime);
                    REFERENCE_TIME dropTime = std::min(graphTime - myTime, remaining - latency);
                    assert(dropTime >= 0);

                    size_t dropFrames = (size_t)llMulDiv(m_device->GetWaveFormat()->nSamplesPerSec,
                                                         dropTime, OneSecond, 0);

                    dropFrames = std::min(dropFrames, chunk.GetFrameCount());

                    if (dropFrames > m_device->GetWaveFormat()->nSamplesPerSec / 33) // ~30ms threshold
                    {
                        chunk.ShrinkHead(chunk.GetFrameCount() - dropFrames);

                        REFERENCE_TIME droppedTime = llMulDiv(dropFrames, OneSecond,
                                                              m_device->GetWaveFormat()->nSamplesPerSec, 0);

                        m_myClock.OffsetSlavedClock(droppedTime);
                        dropTime -= droppedTime;
                        assert(dropTime >= 0);

                        DebugOut("AudioRenderer drop", droppedTime / 10000., "ms for clock matching at",
                                 m_sampleCorrection.GetLastFrameEnd() / 10000., "frame position");
                    }

                    // Correct the rest with variable rate.
                    m_dspRealtimeRate.Adjust(-dropTime);
                    m_myClock.OffsetSlavedClock(dropTime);
                }
            }
        }
    }
Пример #8
0
    SharedWaveFormat AudioRenderer::GetInputFormat()
    {
        CAutoLock objectLock(this);

        return m_inputFormat;
    }
Пример #9
0
    bool AudioRenderer::Finish(bool blockUntilEnd, CAMEvent* pFilledEvent)
    {
        DspChunk chunk;

        {
            CAutoLock objectLock(this);
            assert(m_state != State_Stopped);

            // No device - nothing to block on.
            if (!m_device)
                blockUntilEnd = false;

            try
            {
                // Apply dsp chain.
                if (m_device && !m_device->IsBitstream())
                {
                    auto f = [&](DspBase* pDsp)
                    {
                        pDsp->Finish(chunk);
                    };

                    EnumerateProcessors(f);

                    DspChunk::ToFormat(m_device->GetDspFormat(), chunk);
                }
            }
            catch (std::bad_alloc&)
            {
                chunk = DspChunk();
                assert(chunk.IsEmpty());
            }
        }

        auto doBlock = [&]
        {
            // Increase system timer resolution.
            TimePeriodHelper timePeriodHelper(1);

            for (;;)
            {
                REFERENCE_TIME remaining = 0;

                {
                    CAutoLock objectLock(this);

                    if (m_device)
                    {
                        try
                        {
                            remaining = m_device->Finish(pFilledEvent);
                        }
                        catch (HRESULT)
                        {
                            ClearDevice();
                        }
                    }
                }

                // The end of stream is reached.
                if (remaining <= 0)
                    return true;

                // Sleep until predicted end of stream.
                if (m_flush.Wait(std::max(1, (int32_t)(remaining / OneMillisecond))))
                    return false;
            }
        };

        // Send processed sample to the device, and block until the end of stream (if requested).
        return PushToDevice(chunk, pFilledEvent) && (!blockUntilEnd || doBlock());
    }