| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 
|  | 2 // Use of this source code is governed by a BSD-style license that can be | 
|  | 3 // found in the LICENSE file. | 
|  | 4 | 
|  | 5 #include "base/logging.h" | 
|  | 6 #include "services/media/audio/audio_track_to_output_link.h" | 
|  | 7 | 
|  | 8 namespace mojo { | 
|  | 9 namespace media { | 
|  | 10 namespace audio { | 
|  | 11 | 
|  | 12 AudioTrackToOutputLink::Bookkeeping::~Bookkeeping() {} | 
|  | 13 | 
|  | 14 AudioTrackToOutputLink::AudioTrackToOutputLink(AudioTrackImplWeakPtr track, | 
|  | 15                                                AudioOutputWeakPtr output) | 
|  | 16   : track_(track), | 
|  | 17     output_(output), | 
|  | 18     pending_queue_(new PacketQueue) { | 
|  | 19 #if !(defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)) | 
|  | 20   flush_lock_held_ = false; | 
|  | 21 #endif | 
|  | 22 } | 
|  | 23 | 
|  | 24 AudioTrackToOutputLink::~AudioTrackToOutputLink() { | 
|  | 25   ReleaseQueue(pending_queue_); | 
|  | 26 } | 
|  | 27 | 
|  | 28 AudioTrackToOutputLinkPtr AudioTrackToOutputLink::New( | 
|  | 29     AudioTrackImplWeakPtr track, | 
|  | 30     AudioOutputWeakPtr output) { | 
|  | 31   return AudioTrackToOutputLinkPtr(new AudioTrackToOutputLink(track, output)); | 
|  | 32 } | 
|  | 33 | 
|  | 34 void AudioTrackToOutputLink::PushToPendingQueue( | 
|  | 35     const AudioPipe::AudioPacketRefPtr& pkt) { | 
|  | 36   base::AutoLock lock(pending_queue_lock_); | 
|  | 37   pending_queue_->emplace_back(pkt); | 
|  | 38 } | 
|  | 39 | 
|  | 40 void AudioTrackToOutputLink::FlushPendingQueue() { | 
|  | 41   // Create a new (empty) queue before obtaining any locks.  This will allow us | 
|  | 42   // to quickly swap the empty queue for the current queue and get out of all | 
|  | 43   // the locks, and then release the packets at our leisure instead of | 
|  | 44   // potentially holding off a high priority mixing thread while releasing | 
|  | 45   // packets. | 
|  | 46   // | 
|  | 47   // Note: the safety of this technique depends on Flush only ever being called | 
|  | 48   // from the AudioTrack, and the AudioTrack's actions being serialized on the | 
|  | 49   // AudioServer's message loop thread.  If multiple flushes are allowed to be | 
|  | 50   // invoked simultaniously, or if a packet is permitted to be added to the | 
|  | 51   // queue while a flush operation is in progress, it is possible to return | 
|  | 52   // packets to the user in an order different than the one that they were | 
|  | 53   // queued in. | 
|  | 54   PacketQueuePtr new_queue(new PacketQueue); | 
|  | 55 | 
|  | 56   { | 
|  | 57     base::AutoLock lock(flush_lock_); | 
|  | 58     { | 
|  | 59       // TODO(johngro): Assuming that it is impossible to push a new packet | 
|  | 60       // while a flush is in progress, it's pretty easy to show that this lock | 
|  | 61       // can never be contended.  Because of this, we could consider removing | 
|  | 62       // this lock operation (although, flush is a relatively rare operation, so | 
|  | 63       // the extra overhead is pretty insignificant. | 
|  | 64       base::AutoLock lock(pending_queue_lock_); | 
|  | 65       pending_queue_.swap(new_queue); | 
|  | 66     } | 
|  | 67     flushed_ = true; | 
|  | 68   } | 
|  | 69 | 
|  | 70   ReleaseQueue(new_queue); | 
|  | 71 } | 
|  | 72 | 
|  | 73 AudioPipe::AudioPacketRefPtr AudioTrackToOutputLink::LockPendingQueueFront( | 
|  | 74     bool* was_flushed) { | 
|  | 75 #if !(defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)) | 
|  | 76   // No one had better be holding the flush lock right now.  If someone is, then | 
|  | 77   // we either have multiple threads hitting this operation at the same time | 
|  | 78   // (should be impossible), or an audio output forgot to unlock the front of | 
|  | 79   // the queue before attempting to lock it again. | 
|  | 80   bool was_held = false; | 
|  | 81   flush_lock_held_.compare_exchange_strong(was_held, true); | 
|  | 82   DCHECK(!was_held); | 
|  | 83 #endif | 
|  | 84   flush_lock_.Acquire(); | 
|  | 85 | 
|  | 86   DCHECK(was_flushed); | 
|  | 87   *was_flushed = flushed_; | 
|  | 88   flushed_ = false; | 
|  | 89 | 
|  | 90   { | 
|  | 91     base::AutoLock lock(pending_queue_lock_); | 
|  | 92     if (pending_queue_->size()) { | 
|  | 93       return pending_queue_->front(); | 
|  | 94     } else { | 
|  | 95       return nullptr; | 
|  | 96     } | 
|  | 97   } | 
|  | 98 } | 
|  | 99 | 
|  | 100 void AudioTrackToOutputLink::UnlockPendingQueueFront( | 
|  | 101     AudioPipe::AudioPacketRefPtr* pkt, | 
|  | 102     bool release_packet) { | 
|  | 103   { | 
|  | 104     base::AutoLock lock(pending_queue_lock_); | 
|  | 105 | 
|  | 106     // Assert that the user either got no packet when they locked the queue | 
|  | 107     // (because the queue was empty), or that they got the front of the queue | 
|  | 108     // and that the front of the queue has not changed. | 
|  | 109     DCHECK(pkt); | 
|  | 110     DCHECK((*pkt == nullptr) || | 
|  | 111            (pending_queue_->size() && (*pkt == pending_queue_->front()))); | 
|  | 112 | 
|  | 113     if (*pkt) { | 
|  | 114       *pkt = nullptr; | 
|  | 115       if (release_packet) { | 
|  | 116         pending_queue_->pop_front(); | 
|  | 117       } | 
|  | 118     } | 
|  | 119   } | 
|  | 120 | 
|  | 121   flush_lock_.Release(); | 
|  | 122 #if !(defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)) | 
|  | 123   bool was_held = true; | 
|  | 124   flush_lock_held_.compare_exchange_strong(was_held, false); | 
|  | 125   DCHECK(was_held); | 
|  | 126 #endif | 
|  | 127 } | 
|  | 128 | 
|  | 129 void AudioTrackToOutputLink::ReleaseQueue(const PacketQueuePtr& queue) { | 
|  | 130   if (!queue) { | 
|  | 131     return; | 
|  | 132   } | 
|  | 133 | 
|  | 134   for (auto iter = queue->begin(); iter != queue->end(); ++iter) { | 
|  | 135     (*iter).reset(); | 
|  | 136   } | 
|  | 137 | 
|  | 138   queue->clear(); | 
|  | 139 } | 
|  | 140 | 
|  | 141 }  // namespace audio | 
|  | 142 }  // namespace media | 
|  | 143 }  // namespace mojo | 
|  | 144 | 
| OLD | NEW | 
|---|