• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "ppapi/proxy/media_stream_audio_track_resource.h"
6 
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"
12 
13 namespace ppapi {
14 namespace proxy {
15 
MediaStreamAudioTrackResource(Connection connection,PP_Instance instance,int pending_renderer_id,const std::string & id)16 MediaStreamAudioTrackResource::MediaStreamAudioTrackResource(
17     Connection connection,
18     PP_Instance instance,
19     int pending_renderer_id,
20     const std::string& id)
21     : MediaStreamTrackResourceBase(
22         connection, instance, pending_renderer_id, id),
23       get_buffer_output_(NULL) {
24 }
25 
~MediaStreamAudioTrackResource()26 MediaStreamAudioTrackResource::~MediaStreamAudioTrackResource() {
27   Close();
28 }
29 
30 thunk::PPB_MediaStreamAudioTrack_API*
AsPPB_MediaStreamAudioTrack_API()31 MediaStreamAudioTrackResource::AsPPB_MediaStreamAudioTrack_API() {
32   return this;
33 }
34 
GetId()35 PP_Var MediaStreamAudioTrackResource::GetId() {
36   return StringVar::StringToPPVar(id());
37 }
38 
HasEnded()39 PP_Bool MediaStreamAudioTrackResource::HasEnded() {
40   return PP_FromBool(has_ended());
41 }
42 
Configure(const int32_t attrib_list[],scoped_refptr<TrackedCallback> callback)43 int32_t MediaStreamAudioTrackResource::Configure(
44     const int32_t attrib_list[],
45     scoped_refptr<TrackedCallback> callback) {
46   if (has_ended())
47     return PP_ERROR_FAILED;
48 
49   if (TrackedCallback::IsPending(configure_callback_) ||
50       TrackedCallback::IsPending(get_buffer_callback_)) {
51     return PP_ERROR_INPROGRESS;
52   }
53 
54   // Do not support configure if audio buffers are held by plugin.
55   if (!buffers_.empty())
56     return PP_ERROR_INPROGRESS;
57 
58   MediaStreamAudioTrackShared::Attributes attributes;
59   int i = 0;
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];
64         break;
65       case PP_MEDIASTREAMAUDIOTRACK_ATTRIB_DURATION:
66         attributes.duration = attrib_list[i + 1];
67         break;
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;
72       default:
73         return PP_ERROR_BADARGUMENT;
74     }
75   }
76 
77   if (!MediaStreamAudioTrackShared::VerifyAttributes(attributes))
78     return PP_ERROR_BADARGUMENT;
79 
80   configure_callback_ = callback;
81   Call<PpapiPluginMsg_MediaStreamAudioTrack_ConfigureReply>(
82       RENDERER,
83       PpapiHostMsg_MediaStreamAudioTrack_Configure(attributes),
84       base::Bind(&MediaStreamAudioTrackResource::OnPluginMsgConfigureReply,
85                  base::Unretained(this)),
86       callback);
87   return PP_OK_COMPLETIONPENDING;
88 }
89 
GetAttrib(PP_MediaStreamAudioTrack_Attrib attrib,int32_t * value)90 int32_t MediaStreamAudioTrackResource::GetAttrib(
91     PP_MediaStreamAudioTrack_Attrib attrib,
92     int32_t* value) {
93   // TODO(penghuang): Implement this function.
94   return PP_ERROR_NOTSUPPORTED;
95 }
96 
GetBuffer(PP_Resource * buffer,scoped_refptr<TrackedCallback> callback)97 int32_t MediaStreamAudioTrackResource::GetBuffer(
98     PP_Resource* buffer,
99     scoped_refptr<TrackedCallback> callback) {
100   if (has_ended())
101     return PP_ERROR_FAILED;
102 
103   if (TrackedCallback::IsPending(configure_callback_) ||
104       TrackedCallback::IsPending(get_buffer_callback_))
105     return PP_ERROR_INPROGRESS;
106 
107   *buffer = GetAudioBuffer();
108   if (*buffer)
109     return PP_OK;
110 
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;
117 }
118 
RecycleBuffer(PP_Resource buffer)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;
123 
124   scoped_refptr<AudioBufferResource> buffer_resource = it->second;
125   buffers_.erase(it);
126 
127   if (has_ended())
128     return PP_OK;
129 
130   DCHECK_GE(buffer_resource->GetBufferIndex(), 0);
131 
132   SendEnqueueBufferMessageToHost(buffer_resource->GetBufferIndex());
133   buffer_resource->Invalidate();
134   return PP_OK;
135 }
136 
Close()137 void MediaStreamAudioTrackResource::Close() {
138   if (has_ended())
139     return;
140 
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;
146   }
147 
148   ReleaseBuffers();
149   MediaStreamTrackResourceBase::CloseInternal();
150 }
151 
OnNewBufferEnqueued()152 void MediaStreamAudioTrackResource::OnNewBufferEnqueued() {
153   if (!TrackedCallback::IsPending(get_buffer_callback_))
154     return;
155 
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);
162 }
163 
GetAudioBuffer()164 PP_Resource MediaStreamAudioTrackResource::GetAudioBuffer() {
165   int32_t index = buffer_manager()->DequeueBuffer();
166   if (index < 0)
167       return 0;
168 
169   MediaStreamBuffer* buffer = buffer_manager()->GetBufferPointer(index);
170   DCHECK(buffer);
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
175   // resource alive.
176   buffers_.insert(BufferMap::value_type(resource->pp_resource(), resource));
177   return resource->GetReference();
178 }
179 
ReleaseBuffers()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();
185     it->second = NULL;
186   }
187 }
188 
OnPluginMsgConfigureReply(const ResourceMessageReplyParams & params)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());
195   }
196 }
197 
198 }  // namespace proxy
199 }  // namespace ppapi
200