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 "AsyncAudioDecoder.h"
30
31#include "AudioBuffer.h"
32#include "AudioBufferCallback.h"
33#include <JavaScriptCore/ArrayBuffer.h>
34#include <wtf/MainThread.h>
35
36namespace WebCore {
37
38AsyncAudioDecoder::AsyncAudioDecoder()
39{
40 // Start worker thread.
41 LockHolder lock(m_threadCreationMutex);
42 m_thread = Thread::create("Audio Decoder", [this] {
43 runLoop();
44 });
45}
46
47AsyncAudioDecoder::~AsyncAudioDecoder()
48{
49 m_queue.kill();
50
51 // Stop thread.
52 m_thread->waitForCompletion();
53}
54
55void AsyncAudioDecoder::decodeAsync(Ref<ArrayBuffer>&& audioData, float sampleRate, RefPtr<AudioBufferCallback>&& successCallback, RefPtr<AudioBufferCallback>&& errorCallback)
56{
57 ASSERT(isMainThread());
58
59 auto decodingTask = std::make_unique<DecodingTask>(WTFMove(audioData), sampleRate, WTFMove(successCallback), WTFMove(errorCallback));
60 m_queue.append(WTFMove(decodingTask)); // note that ownership of the task is effectively taken by the queue.
61}
62
63void AsyncAudioDecoder::runLoop()
64{
65 ASSERT(!isMainThread());
66
67 {
68 // Wait for until we have m_thread established before starting the run loop.
69 LockHolder lock(m_threadCreationMutex);
70 }
71
72 // Keep running decoding tasks until we're killed.
73 while (auto decodingTask = m_queue.waitForMessage()) {
74 // Let the task take care of its own ownership.
75 // See DecodingTask::notifyComplete() for cleanup.
76 decodingTask.release()->decode();
77 }
78}
79
80AsyncAudioDecoder::DecodingTask::DecodingTask(Ref<ArrayBuffer>&& audioData, float sampleRate, RefPtr<AudioBufferCallback>&& successCallback, RefPtr<AudioBufferCallback>&& errorCallback)
81 : m_audioData(WTFMove(audioData))
82 , m_sampleRate(sampleRate)
83 , m_successCallback(WTFMove(successCallback))
84 , m_errorCallback(WTFMove(errorCallback))
85{
86}
87
88void AsyncAudioDecoder::DecodingTask::decode()
89{
90 // Do the actual decoding and invoke the callback.
91 m_audioBuffer = AudioBuffer::createFromAudioFileData(m_audioData->data(), m_audioData->byteLength(), false, sampleRate());
92
93 // Decoding is finished, but we need to do the callbacks on the main thread.
94 callOnMainThread([this] {
95 notifyComplete();
96 });
97}
98
99void AsyncAudioDecoder::DecodingTask::notifyComplete()
100{
101 if (audioBuffer() && successCallback())
102 successCallback()->handleEvent(audioBuffer());
103 else if (errorCallback())
104 errorCallback()->handleEvent(audioBuffer());
105
106 // Our ownership was given up in AsyncAudioDecoder::runLoop()
107 // Make sure to clean up here.
108 delete this;
109}
110
111} // namespace WebCore
112
113#endif // ENABLE(WEB_AUDIO)
114