f5ac3181f5390beed2f40c1f1c280ad4442cd906
[WebKit-https.git] / Source / WebKit / WebProcess / GPU / webrtc / MediaRecorderPrivate.cpp
1 /*
2  * Copyright (C) 2020 Apple 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''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "MediaRecorderPrivate.h"
28
29 #if PLATFORM(COCOA) && ENABLE(GPU_PROCESS) && ENABLE(MEDIA_STREAM) && HAVE(AVASSETWRITERDELEGATE)
30
31 #include "DataReference.h"
32 #include "GPUProcessConnection.h"
33 #include "RemoteMediaRecorderManagerMessages.h"
34 #include "RemoteMediaRecorderMessages.h"
35 #include "WebProcess.h"
36 #include <WebCore/CARingBuffer.h>
37 #include <WebCore/MediaStreamPrivate.h>
38 #include <WebCore/MediaStreamTrackPrivate.h>
39 #include <WebCore/RemoteVideoSample.h>
40 #include <WebCore/SharedBuffer.h>
41 #include <WebCore/WebAudioBufferList.h>
42
43 namespace WebKit {
44 using namespace WebCore;
45
46 MediaRecorderPrivate::MediaRecorderPrivate(MediaStreamPrivate& stream)
47     : m_identifier(MediaRecorderIdentifier::generate())
48     , m_connection(WebProcess::singleton().ensureGPUProcessConnection().connection())
49 {
50     // FIXME: we will need to implement support for multiple audio/video tracks
51     // Currently we only choose the first track as the recorded track.
52
53     auto selectedTracks = MediaRecorderPrivate::selectTracks(stream);
54     if (selectedTracks.audioTrack) {
55         m_ringBuffer = makeUnique<CARingBuffer>(makeUniqueRef<SharedRingBufferStorage>(this));
56         m_recordedAudioTrackID = selectedTracks.audioTrack->id();
57     }
58
59     int width = 0;
60     int height = 0;
61     if (selectedTracks.videoTrack) {
62         m_recordedVideoTrackID = selectedTracks.videoTrack->id();
63         height = selectedTracks.videoTrack->settings().height();
64         width = selectedTracks.videoTrack->settings().width();
65     }
66
67     m_connection->sendWithAsyncReply(Messages::RemoteMediaRecorderManager::CreateRecorder { m_identifier, !!selectedTracks.audioTrack, width, height }, [this, weakThis = makeWeakPtr(this), audioTrack = makeRefPtr(selectedTracks.audioTrack), videoTrack = makeRefPtr(selectedTracks.videoTrack)](auto&& exception) {
68         if (!weakThis)
69             return;
70         if (exception)
71             return m_errorCallback(Exception { exception->code, WTFMove(exception->message) });
72         if (audioTrack)
73             setAudioSource(&audioTrack->source());
74         if (videoTrack)
75             setVideoSource(&videoTrack->source());
76     }, 0);
77 }
78
79 MediaRecorderPrivate::~MediaRecorderPrivate()
80 {
81     setAudioSource(nullptr);
82     setVideoSource(nullptr);
83     m_connection->send(Messages::RemoteMediaRecorderManager::ReleaseRecorder { m_identifier }, 0);
84 }
85
86 void MediaRecorderPrivate::videoSampleAvailable(MediaSample& sample)
87 {
88     if (auto remoteSample = RemoteVideoSample::create(sample))
89         m_connection->send(Messages::RemoteMediaRecorder::VideoSampleAvailable { WTFMove(*remoteSample) }, m_identifier);
90 }
91
92 void MediaRecorderPrivate::audioSamplesAvailable(const MediaTime& time, const PlatformAudioData& audioData, const AudioStreamDescription& description, size_t numberOfFrames)
93 {
94     if (m_description != description) {
95         ASSERT(description.platformDescription().type == PlatformDescription::CAAudioStreamBasicType);
96         m_description = *WTF::get<const AudioStreamBasicDescription*>(description.platformDescription().description);
97
98         // Allocate a ring buffer large enough to contain 2 seconds of audio.
99         m_numberOfFrames = m_description.sampleRate() * 2;
100         m_ringBuffer->allocate(m_description.streamDescription(), m_numberOfFrames);
101     }
102
103     ASSERT(is<WebAudioBufferList>(audioData));
104     m_ringBuffer->store(downcast<WebAudioBufferList>(audioData).list(), numberOfFrames, time.timeValue());
105     uint64_t startFrame;
106     uint64_t endFrame;
107     m_ringBuffer->getCurrentFrameBounds(startFrame, endFrame);
108     m_connection->send(Messages::RemoteMediaRecorder::AudioSamplesAvailable { time, numberOfFrames, startFrame, endFrame }, m_identifier);
109 }
110
111 void MediaRecorderPrivate::storageChanged(SharedMemory* storage)
112 {
113     SharedMemory::Handle handle;
114     if (storage)
115         storage->createHandle(handle, SharedMemory::Protection::ReadOnly);
116     m_connection->send(Messages::RemoteMediaRecorder::AudioSamplesStorageChanged { handle, m_description, static_cast<uint64_t>(m_numberOfFrames) }, m_identifier);
117 }
118
119 void MediaRecorderPrivate::fetchData(CompletionHandler<void(RefPtr<WebCore::SharedBuffer>&&, const String& mimeType)>&& completionHandler)
120 {
121     m_connection->sendWithAsyncReply(Messages::RemoteMediaRecorder::FetchData { }, [completionHandler = WTFMove(completionHandler)](auto&& data, auto&& mimeType) mutable {
122         RefPtr<SharedBuffer> buffer;
123         if (data.size())
124             buffer = SharedBuffer::create(data.data(), data.size());
125         completionHandler(WTFMove(buffer), mimeType);
126     }, m_identifier);
127 }
128
129 void MediaRecorderPrivate::stopRecording()
130 {
131     setAudioSource(nullptr);
132     setVideoSource(nullptr);
133     m_connection->send(Messages::RemoteMediaRecorder::StopRecording { }, m_identifier);
134 }
135
136 }
137
138 #endif // PLATFORM(COCOA) && ENABLE(GPU_PROCESS) && ENABLE(MEDIA_STREAM) && HAVE(AVASSETWRITERDELEGATE)