1 // Copyright 2014 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.
5 #include "ppapi/proxy/media_stream_audio_track_resource.h"
7 #include "ppapi/proxy/audio_buffer_resource.h"
8 #include "ppapi/proxy/ppapi_messages.h"
9 #include "ppapi/shared_impl/media_stream_audio_track_shared.h"
10 #include "ppapi/shared_impl/media_stream_buffer.h"
11 #include "ppapi/shared_impl/var.h"
16 MediaStreamAudioTrackResource::MediaStreamAudioTrackResource(
17 Connection connection
,
19 int pending_renderer_id
,
20 const std::string
& id
)
21 : MediaStreamTrackResourceBase(
22 connection
, instance
, pending_renderer_id
, id
),
23 get_buffer_output_(NULL
) {
26 MediaStreamAudioTrackResource::~MediaStreamAudioTrackResource() {
30 thunk::PPB_MediaStreamAudioTrack_API
*
31 MediaStreamAudioTrackResource::AsPPB_MediaStreamAudioTrack_API() {
35 PP_Var
MediaStreamAudioTrackResource::GetId() {
36 return StringVar::StringToPPVar(id());
39 PP_Bool
MediaStreamAudioTrackResource::HasEnded() {
40 return PP_FromBool(has_ended());
43 int32_t MediaStreamAudioTrackResource::Configure(
44 const int32_t attrib_list
[],
45 scoped_refptr
<TrackedCallback
> callback
) {
47 return PP_ERROR_FAILED
;
49 if (TrackedCallback::IsPending(configure_callback_
) ||
50 TrackedCallback::IsPending(get_buffer_callback_
)) {
51 return PP_ERROR_INPROGRESS
;
54 // Do not support configure if audio buffers are held by plugin.
55 if (!buffers_
.empty())
56 return PP_ERROR_INPROGRESS
;
58 MediaStreamAudioTrackShared::Attributes attributes
;
60 for (; attrib_list
[i
] != PP_MEDIASTREAMAUDIOTRACK_ATTRIB_NONE
; i
+= 2) {
61 switch (attrib_list
[i
]) {
62 case PP_MEDIASTREAMAUDIOTRACK_ATTRIB_BUFFERS
:
63 attributes
.buffers
= attrib_list
[i
+ 1];
65 case PP_MEDIASTREAMAUDIOTRACK_ATTRIB_DURATION
:
66 attributes
.duration
= attrib_list
[i
+ 1];
68 case PP_MEDIASTREAMAUDIOTRACK_ATTRIB_SAMPLE_RATE
:
69 case PP_MEDIASTREAMAUDIOTRACK_ATTRIB_SAMPLE_SIZE
:
70 case PP_MEDIASTREAMAUDIOTRACK_ATTRIB_CHANNELS
:
71 return PP_ERROR_NOTSUPPORTED
;
73 return PP_ERROR_BADARGUMENT
;
77 if (!MediaStreamAudioTrackShared::VerifyAttributes(attributes
))
78 return PP_ERROR_BADARGUMENT
;
80 configure_callback_
= callback
;
81 Call
<PpapiPluginMsg_MediaStreamAudioTrack_ConfigureReply
>(
83 PpapiHostMsg_MediaStreamAudioTrack_Configure(attributes
),
84 base::Bind(&MediaStreamAudioTrackResource::OnPluginMsgConfigureReply
,
85 base::Unretained(this)),
87 return PP_OK_COMPLETIONPENDING
;
90 int32_t MediaStreamAudioTrackResource::GetAttrib(
91 PP_MediaStreamAudioTrack_Attrib attrib
,
93 // TODO(penghuang): Implement this function.
94 return PP_ERROR_NOTSUPPORTED
;
97 int32_t MediaStreamAudioTrackResource::GetBuffer(
99 scoped_refptr
<TrackedCallback
> callback
) {
101 return PP_ERROR_FAILED
;
103 if (TrackedCallback::IsPending(configure_callback_
) ||
104 TrackedCallback::IsPending(get_buffer_callback_
))
105 return PP_ERROR_INPROGRESS
;
107 *buffer
= GetAudioBuffer();
111 // TODO(penghuang): Use the callback as hints to determine which thread will
112 // use the resource, so we could deliver buffers to the target thread directly
113 // for better performance.
114 get_buffer_output_
= buffer
;
115 get_buffer_callback_
= callback
;
116 return PP_OK_COMPLETIONPENDING
;
119 int32_t MediaStreamAudioTrackResource::RecycleBuffer(PP_Resource buffer
) {
120 BufferMap::iterator it
= buffers_
.find(buffer
);
121 if (it
== buffers_
.end())
122 return PP_ERROR_BADRESOURCE
;
124 scoped_refptr
<AudioBufferResource
> buffer_resource
= it
->second
;
130 DCHECK_GE(buffer_resource
->GetBufferIndex(), 0);
132 SendEnqueueBufferMessageToHost(buffer_resource
->GetBufferIndex());
133 buffer_resource
->Invalidate();
137 void MediaStreamAudioTrackResource::Close() {
141 if (TrackedCallback::IsPending(get_buffer_callback_
)) {
142 *get_buffer_output_
= 0;
143 get_buffer_callback_
->PostAbort();
144 get_buffer_callback_
= NULL
;
145 get_buffer_output_
= 0;
149 MediaStreamTrackResourceBase::CloseInternal();
152 void MediaStreamAudioTrackResource::OnNewBufferEnqueued() {
153 if (!TrackedCallback::IsPending(get_buffer_callback_
))
156 *get_buffer_output_
= GetAudioBuffer();
157 int32_t result
= *get_buffer_output_
? PP_OK
: PP_ERROR_FAILED
;
158 get_buffer_output_
= NULL
;
159 scoped_refptr
<TrackedCallback
> callback
;
160 callback
.swap(get_buffer_callback_
);
161 callback
->Run(result
);
164 PP_Resource
MediaStreamAudioTrackResource::GetAudioBuffer() {
165 int32_t index
= buffer_manager()->DequeueBuffer();
169 MediaStreamBuffer
* buffer
= buffer_manager()->GetBufferPointer(index
);
171 scoped_refptr
<AudioBufferResource
> resource
=
172 new AudioBufferResource(pp_instance(), index
, buffer
);
173 // Add |pp_resource()| and |resource| into |buffers_|.
174 // |buffers_| uses scoped_ptr<> to hold a ref of |resource|. It keeps the
176 buffers_
.insert(BufferMap::value_type(resource
->pp_resource(), resource
));
177 return resource
->GetReference();
180 void MediaStreamAudioTrackResource::ReleaseBuffers() {
181 for (BufferMap::iterator it
= buffers_
.begin(); it
!= buffers_
.end(); ++it
) {
182 // Just invalidate and release VideoBufferResorce, but keep PP_Resource.
183 // So plugin can still use |RecycleBuffer()|.
184 it
->second
->Invalidate();
189 void MediaStreamAudioTrackResource::OnPluginMsgConfigureReply(
190 const ResourceMessageReplyParams
& params
) {
191 if (TrackedCallback::IsPending(configure_callback_
)) {
192 scoped_refptr
<TrackedCallback
> callback
;
193 callback
.swap(configure_callback_
);
194 callback
->Run(params
.result());