Home | History | Annotate | Download | only in proxy
      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