Home | History | Annotate | Download | only in webaudio
      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