1 /* 2 * Copyright (C) 2011, Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY 17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 */ 24 25 #include "config.h" 26 27 #if ENABLE(WEB_AUDIO) 28 29 #include "modules/webaudio/AsyncAudioDecoder.h" 30 31 #include "modules/webaudio/AudioBuffer.h" 32 #include "modules/webaudio/AudioBufferCallback.h" 33 #include "wtf/ArrayBuffer.h" 34 #include "wtf/MainThread.h" 35 #include "wtf/OwnPtr.h" 36 #include "wtf/PassOwnPtr.h" 37 38 namespace WebCore { 39 40 AsyncAudioDecoder::AsyncAudioDecoder() 41 { 42 // Start worker thread. 43 MutexLocker lock(m_threadCreationMutex); 44 m_threadID = createThread(AsyncAudioDecoder::threadEntry, this, "Audio Decoder"); 45 } 46 47 AsyncAudioDecoder::~AsyncAudioDecoder() 48 { 49 m_queue.kill(); 50 51 // Stop thread. 52 waitForThreadCompletion(m_threadID); 53 m_threadID = 0; 54 } 55 56 void AsyncAudioDecoder::decodeAsync(ArrayBuffer* audioData, float sampleRate, PassRefPtr<AudioBufferCallback> successCallback, PassRefPtr<AudioBufferCallback> errorCallback) 57 { 58 ASSERT(isMainThread()); 59 ASSERT(audioData); 60 if (!audioData) 61 return; 62 63 OwnPtr<DecodingTask> decodingTask = DecodingTask::create(audioData, sampleRate, successCallback, errorCallback); 64 m_queue.append(decodingTask.release()); // note that ownership of the task is effectively taken by the queue. 65 } 66 67 // Asynchronously decode in this thread. 68 void AsyncAudioDecoder::threadEntry(void* threadData) 69 { 70 ASSERT(threadData); 71 AsyncAudioDecoder* decoder = reinterpret_cast<AsyncAudioDecoder*>(threadData); 72 decoder->runLoop(); 73 } 74 75 void AsyncAudioDecoder::runLoop() 76 { 77 ASSERT(!isMainThread()); 78 79 { 80 // Wait for until we have m_threadID established before starting the run loop. 81 MutexLocker lock(m_threadCreationMutex); 82 } 83 84 // Keep running decoding tasks until we're killed. 85 while (OwnPtr<DecodingTask> decodingTask = m_queue.waitForMessage()) { 86 // Let the task take care of its own ownership. 87 // See DecodingTask::notifyComplete() for cleanup. 88 decodingTask.leakPtr()->decode(); 89 } 90 } 91 92 PassOwnPtr<AsyncAudioDecoder::DecodingTask> AsyncAudioDecoder::DecodingTask::create(ArrayBuffer* audioData, float sampleRate, PassRefPtr<AudioBufferCallback> successCallback, PassRefPtr<AudioBufferCallback> errorCallback) 93 { 94 return adoptPtr(new DecodingTask(audioData, sampleRate, successCallback, errorCallback)); 95 } 96 97 AsyncAudioDecoder::DecodingTask::DecodingTask(ArrayBuffer* audioData, float sampleRate, PassRefPtr<AudioBufferCallback> successCallback, PassRefPtr<AudioBufferCallback> errorCallback) 98 : m_audioData(audioData) 99 , m_sampleRate(sampleRate) 100 , m_successCallback(successCallback) 101 , m_errorCallback(errorCallback) 102 { 103 } 104 105 void AsyncAudioDecoder::DecodingTask::decode() 106 { 107 ASSERT(m_audioData.get()); 108 if (!m_audioData.get()) 109 return; 110 111 // Do the actual decoding and invoke the callback. 112 m_audioBuffer = AudioBuffer::createFromAudioFileData(m_audioData->data(), m_audioData->byteLength(), false, sampleRate()); 113 114 // Decoding is finished, but we need to do the callbacks on the main thread. 115 callOnMainThread(notifyCompleteDispatch, this); 116 } 117 118 void AsyncAudioDecoder::DecodingTask::notifyCompleteDispatch(void* userData) 119 { 120 AsyncAudioDecoder::DecodingTask* task = reinterpret_cast<AsyncAudioDecoder::DecodingTask*>(userData); 121 ASSERT(task); 122 if (!task) 123 return; 124 125 task->notifyComplete(); 126 } 127 128 void AsyncAudioDecoder::DecodingTask::notifyComplete() 129 { 130 if (audioBuffer() && successCallback()) 131 successCallback()->handleEvent(audioBuffer()); 132 else if (errorCallback()) 133 errorCallback()->handleEvent(audioBuffer()); 134 135 // Our ownership was given up in AsyncAudioDecoder::runLoop() 136 // Make sure to clean up here. 137 delete this; 138 } 139 140 } // namespace WebCore 141 142 #endif // ENABLE(WEB_AUDIO) 143