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 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 26 MediaStreamAudioTrackResource::~MediaStreamAudioTrackResource() { 27 Close(); 28 } 29 30 thunk::PPB_MediaStreamAudioTrack_API* 31 MediaStreamAudioTrackResource::AsPPB_MediaStreamAudioTrack_API() { 32 return this; 33 } 34 35 PP_Var MediaStreamAudioTrackResource::GetId() { 36 return StringVar::StringToPPVar(id()); 37 } 38 39 PP_Bool MediaStreamAudioTrackResource::HasEnded() { 40 return PP_FromBool(has_ended()); 41 } 42 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 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 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 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 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 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 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 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 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