Changeset 261063 in webkit


Ignore:
Timestamp:
May 3, 2020 11:16:31 AM (4 years ago)
Author:
youenn@apple.com
Message:

AudioMediaStreamTrackRendererCocoa should create/start/stop its remote unit on the main thread
https://bugs.webkit.org/show_bug.cgi?id=211287

Reviewed by Eric Carlson.

Creating/starting/stopping audio units in different threads is error prone.
Now that we have an observer model where we have observers for when to play in the main thread and
based on that, we decide to receive audio samples in a background thread, we can simplify the logic of AudioMediaStreamTrackRendererCocoa.
We do this by creating/starting the unit in AudioMediaStreamTrackRendererCocoa::start.
At that point, AudioMediaStreamTrackRendererCocoa is not expected to receive any sample.
Just after starting, AudioTrackPrivateMediaStream will receive audio samples and forward them to AudioMediaStreamTrackRendererCocoa.
AudioMediaStreamTrackRendererCocoa will then create in a background thread the AudioSampleDataSource that is responsible to adapt the received audio samples to the unit.

Manually tested.

  • platform/audio/mac/AudioSampleDataSource.h:

(WebCore::AudioSampleDataSource::inputDescription const):

  • platform/audio/mac/CAAudioStreamDescription.h:
  • platform/mediastream/AudioTrackPrivateMediaStream.cpp:

(WebCore::AudioTrackPrivateMediaStream::startRenderer):
Ensure to start the unit and then start gettting audio samples.

  • platform/mediastream/mac/AudioMediaStreamTrackRendererCocoa.cpp:

(WebCore::AudioMediaStreamTrackRendererCocoa::start):
(WebCore::AudioMediaStreamTrackRendererCocoa::stop):
(WebCore::AudioMediaStreamTrackRendererCocoa::clear):
(WebCore::AudioMediaStreamTrackRendererCocoa::pushSamples):
(WebCore::AudioMediaStreamTrackRendererCocoa::render):

  • platform/mediastream/mac/AudioMediaStreamTrackRendererCocoa.h:
Location:
trunk/Source/WebCore
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r261061 r261063  
     12020-05-03  Youenn Fablet  <youenn@apple.com>
     2
     3        AudioMediaStreamTrackRendererCocoa should create/start/stop its remote unit on the main thread
     4        https://bugs.webkit.org/show_bug.cgi?id=211287
     5
     6        Reviewed by Eric Carlson.
     7
     8        Creating/starting/stopping audio units in different threads is error prone.
     9        Now that we have an observer model where we have observers for when to play in the main thread and
     10        based on that, we decide to receive audio samples in a background thread, we can simplify the logic of AudioMediaStreamTrackRendererCocoa.
     11        We do this by creating/starting the unit in AudioMediaStreamTrackRendererCocoa::start.
     12        At that point, AudioMediaStreamTrackRendererCocoa is not expected to receive any sample.
     13        Just after starting, AudioTrackPrivateMediaStream will receive audio samples and forward them to AudioMediaStreamTrackRendererCocoa.
     14        AudioMediaStreamTrackRendererCocoa will then create in a background thread the AudioSampleDataSource that is responsible to adapt the received audio samples to the unit.
     15
     16        Manually tested.
     17
     18        * platform/audio/mac/AudioSampleDataSource.h:
     19        (WebCore::AudioSampleDataSource::inputDescription const):
     20        * platform/audio/mac/CAAudioStreamDescription.h:
     21        * platform/mediastream/AudioTrackPrivateMediaStream.cpp:
     22        (WebCore::AudioTrackPrivateMediaStream::startRenderer):
     23        Ensure to start the unit and then start gettting audio samples.
     24        * platform/mediastream/mac/AudioMediaStreamTrackRendererCocoa.cpp:
     25        (WebCore::AudioMediaStreamTrackRendererCocoa::start):
     26        (WebCore::AudioMediaStreamTrackRendererCocoa::stop):
     27        (WebCore::AudioMediaStreamTrackRendererCocoa::clear):
     28        (WebCore::AudioMediaStreamTrackRendererCocoa::pushSamples):
     29        (WebCore::AudioMediaStreamTrackRendererCocoa::render):
     30        * platform/mediastream/mac/AudioMediaStreamTrackRendererCocoa.h:
     31
    1322020-05-03  Rob Buis  <rbuis@igalia.com>
    233
  • trunk/Source/WebCore/platform/audio/mac/AudioSampleDataSource.h

    r254446 r261063  
    7474    bool muted() const { return m_muted; }
    7575
     76    const CAAudioStreamDescription* inputDescription() const { return m_inputDescription.get(); }
     77
    7678#if !RELEASE_LOG_DISABLED
    7779    const Logger& logger() const final { return m_logger; }
  • trunk/Source/WebCore/platform/audio/mac/CAAudioStreamDescription.h

    r260078 r261063  
    6565    uint32_t formatFlags() const { return m_streamDescription.mFormatFlags; }
    6666
    67     bool operator==(const AudioStreamBasicDescription& other) { return m_streamDescription == other; }
    68     bool operator!=(const AudioStreamBasicDescription& other) { return !operator == (other); }
    69     bool operator==(const AudioStreamDescription& other)
     67    bool operator==(const AudioStreamBasicDescription& other) const { return m_streamDescription == other; }
     68    bool operator!=(const AudioStreamBasicDescription& other) const { return !operator == (other); }
     69    bool operator==(const AudioStreamDescription& other) const
    7070    {
    7171        if (other.platformDescription().type != PlatformDescription::CAAudioStreamBasicType)
     
    7474        return operator==(*WTF::get<const AudioStreamBasicDescription*>(other.platformDescription().description));
    7575    }
    76     bool operator!=(const AudioStreamDescription& other) { return !operator == (other); }
     76    bool operator!=(const AudioStreamDescription& other) const { return !operator == (other); }
    7777
    7878    const AudioStreamBasicDescription& streamDescription() const { return m_streamDescription; }
  • trunk/Source/WebCore/platform/mediastream/AudioMediaStreamTrackRenderer.h

    r254562 r261063  
    4848    virtual void stop() = 0;
    4949    virtual void clear() = 0;
    50     // May be called on a background thread.
     50    // May be called on a background thread. It should only be called after start/before stop is called.
    5151    virtual void pushSamples(const WTF::MediaTime&, const PlatformAudioData&, const AudioStreamDescription&, size_t) = 0;
    5252
  • trunk/Source/WebCore/platform/mediastream/AudioTrackPrivateMediaStream.cpp

    r260380 r261063  
    140140
    141141    m_isPlaying = true;
     142    m_renderer->start();
    142143    m_audioSource->addAudioSampleObserver(*this);
    143     m_renderer->start();
    144144}
    145145
  • trunk/Source/WebCore/platform/mediastream/mac/AudioMediaStreamTrackRendererCocoa.cpp

    r258839 r261063  
    4848    clear();
    4949
    50     m_shouldPlay = true;
     50    CAAudioStreamDescription outputDescription;
     51    auto remoteIOUnit = createAudioUnit(outputDescription);
     52    if (!remoteIOUnit)
     53        return;
    5154
    52     if (m_dataSource)
    53         m_dataSource->setPaused(false);
     55    if (auto error = AudioOutputUnitStart(remoteIOUnit)) {
     56        ERROR_LOG(LOGIDENTIFIER, "AudioOutputUnitStart failed, error = ", error, " (", (const char*)&error, ")");
     57        AudioComponentInstanceDispose(remoteIOUnit);
     58        return;
     59    }
     60    m_outputDescription = makeUnique<CAAudioStreamDescription>(outputDescription);
     61    m_remoteIOUnit = remoteIOUnit;
    5462}
    5563
    5664void AudioMediaStreamTrackRendererCocoa::stop()
    5765{
    58     m_shouldPlay = false;
     66    if (!m_remoteIOUnit)
     67        return;
    5968
    60     if (m_dataSource)
    61         m_dataSource->setPaused(true);
     69    AudioOutputUnitStop(m_remoteIOUnit);
     70    AudioComponentInstanceDispose(m_remoteIOUnit);
     71    m_remoteIOUnit = nullptr;
    6272}
    6373
    6474void AudioMediaStreamTrackRendererCocoa::clear()
    6575{
    66     m_shouldPlay = false;
    67 
    68     if (m_dataSource)
    69         m_dataSource->setPaused(true);
    70 
    71     if (m_remoteIOUnit) {
    72         AudioOutputUnitStop(m_remoteIOUnit);
    73         AudioComponentInstanceDispose(m_remoteIOUnit);
    74         m_remoteIOUnit = nullptr;
    75     }
     76    stop();
    7677
    7778    m_dataSource = nullptr;
    78     m_inputDescription = nullptr;
    7979    m_outputDescription = nullptr;
    80     m_isAudioUnitStarted = false;
    8180}
    8281
     
    149148{
    150149    ASSERT(description.platformDescription().type == PlatformDescription::CAAudioStreamBasicType);
    151     if (!m_shouldPlay) {
    152         if (m_isAudioUnitStarted) {
    153             if (m_remoteIOUnit)
    154                 AudioOutputUnitStop(m_remoteIOUnit);
    155             m_isAudioUnitStarted = false;
    156         }
     150    if (!m_remoteIOUnit)
    157151        return;
    158     }
    159152
    160     if (!m_inputDescription || *m_inputDescription != description) {
    161         m_isAudioUnitStarted = false;
     153    if (!m_dataSource || !m_dataSource->inputDescription() || *m_dataSource->inputDescription() != description) {
     154        auto dataSource = AudioSampleDataSource::create(description.sampleRate() * 2, *this);
    162155
    163         if (m_remoteIOUnit) {
    164             AudioOutputUnitStop(m_remoteIOUnit);
    165             AudioComponentInstanceDispose(m_remoteIOUnit);
    166             m_remoteIOUnit = nullptr;
    167         }
    168 
    169         m_inputDescription = nullptr;
    170         m_outputDescription = nullptr;
    171 
    172         CAAudioStreamDescription inputDescription = toCAAudioStreamDescription(description);
    173         CAAudioStreamDescription outputDescription;
    174 
    175         auto remoteIOUnit = createAudioUnit(outputDescription);
    176         if (!remoteIOUnit)
    177             return;
    178 
    179         m_inputDescription = makeUnique<CAAudioStreamDescription>(inputDescription);
    180         m_outputDescription = makeUnique<CAAudioStreamDescription>(outputDescription);
    181 
    182         m_dataSource = AudioSampleDataSource::create(description.sampleRate() * 2, *this);
    183 
    184         if (m_dataSource->setInputFormat(inputDescription) || m_dataSource->setOutputFormat(outputDescription)) {
    185             AudioComponentInstanceDispose(remoteIOUnit);
     156        if (dataSource->setInputFormat(toCAAudioStreamDescription(description))) {
     157            ERROR_LOG(LOGIDENTIFIER, "Unable to set the input format of data source");
    186158            return;
    187159        }
    188160
    189         if (auto error = AudioOutputUnitStart(remoteIOUnit)) {
    190             ERROR_LOG(LOGIDENTIFIER, "AudioOutputUnitStart failed, error = ", error, " (", (const char*)&error, ")");
    191             AudioComponentInstanceDispose(remoteIOUnit);
    192             m_inputDescription = nullptr;
     161        if (dataSource->setOutputFormat(*m_outputDescription)) {
     162            ERROR_LOG(LOGIDENTIFIER, "Unable to set the output format of data source");
    193163            return;
    194164        }
    195165
    196         m_isAudioUnitStarted = true;
     166        dataSource->setPaused(false);
     167        dataSource->setVolume(volume());
    197168
    198         m_dataSource->setVolume(volume());
    199         m_remoteIOUnit = remoteIOUnit;
     169        m_dataSource = WTFMove(dataSource);
    200170    }
    201171
    202172    m_dataSource->pushSamples(sampleTime, audioData, sampleCount);
    203 
    204     if (!m_isAudioUnitStarted) {
    205         if (auto error = AudioOutputUnitStart(m_remoteIOUnit)) {
    206             ERROR_LOG(LOGIDENTIFIER, "AudioOutputUnitStart failed, error = ", error, " (", (const char*)&error, ")");
    207             return;
    208         }
    209         m_isAudioUnitStarted = true;
    210     }
    211173}
    212174
     175// May get called on a background thread.
    213176OSStatus AudioMediaStreamTrackRendererCocoa::render(UInt32 sampleCount, AudioBufferList& ioData, UInt32 /*inBusNumber*/, const AudioTimeStamp& timeStamp, AudioUnitRenderActionFlags& actionFlags)
    214177{
    215     if (isMuted() || !m_shouldPlay || !m_dataSource) {
     178    auto dataSource = m_dataSource;
     179    if (!dataSource) {
    216180        AudioSampleBufferList::zeroABL(ioData, static_cast<size_t>(sampleCount * m_outputDescription->bytesPerFrame()));
    217181        actionFlags = kAudioUnitRenderAction_OutputIsSilence;
     
    219183    }
    220184
    221     m_dataSource->pullSamples(ioData, static_cast<size_t>(sampleCount), timeStamp.mSampleTime, timeStamp.mHostTime, AudioSampleDataSource::Copy);
    222 
     185    dataSource->pullSamples(ioData, static_cast<size_t>(sampleCount), timeStamp.mSampleTime, timeStamp.mHostTime, AudioSampleDataSource::Copy);
    223186    return 0;
    224187}
  • trunk/Source/WebCore/platform/mediastream/mac/AudioMediaStreamTrackRendererCocoa.h

    r254562 r261063  
    5858    AudioComponentInstance createAudioUnit(CAAudioStreamDescription&);
    5959
    60     // Audio thread members
    6160    AudioComponentInstance m_remoteIOUnit { nullptr };
    62     std::unique_ptr<CAAudioStreamDescription> m_inputDescription;
    6361    std::unique_ptr<CAAudioStreamDescription> m_outputDescription;
    6462
    65     // Cross thread members
     63    // Audio threads member
    6664    RefPtr<AudioSampleDataSource> m_dataSource;
    67     bool m_isAudioUnitStarted { false };
    68     bool m_shouldPlay { false };
    6965};
    7066
Note: See TracChangeset for help on using the changeset viewer.