精华内容
下载资源
问答
  • Traceback (most recent call last): File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 1317, in do_open encode_chunked=req.has_header('Transfer-encodi...
    Traceback (most recent call last):
      File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 1317, in do_open
        encode_chunked=req.has_header('Transfer-encoding'))
      File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/http/client.py", line 1244, in request
        self._send_request(method, url, body, headers, encode_chunked)
      File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/http/client.py", line 1290, in _send_request
        self.endheaders(body, encode_chunked=encode_chunked)
      File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/http/client.py", line 1239, in endheaders
        self._send_output(message_body, encode_chunked=encode_chunked)
      File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/http/client.py", line 1026, in _send_output
        self.send(msg)
      File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/http/client.py", line 966, in send
        self.connect()
      File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/http/client.py", line 1414, in connect
        server_hostname=server_hostname)
      File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ssl.py", line 423, in wrap_socket
        session=session
      File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ssl.py", line 870, in _create
        self.do_handshake()
      File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ssl.py", line 1139, in do_handshake
        self._sslobj.do_handshake()
    ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1076)
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "/Users/wangyang_data/PycharmProjects/爬虫day01/01-url_opne_code.py", line 14, in <module>
        load_data()
      File "/Users/wangyang_data/PycharmProjects/爬虫day01/01-url_opne_code.py", line 11, in load_data
        response = urllib.request.urlopen(url)
      File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 222, in urlopen
        return opener.open(url, data, timeout)
      File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 525, in open
        response = self._open(req, data)
      File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 543, in _open
        '_open', req)
      File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 503, in _call_chain
        result = func(*args)
      File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 1360, in https_open
        context=self._context, check_hostname=self._check_hostname)
      File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 1319, in do_open
        raise URLError(err)
    urllib.error.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1076)>
    
    Process finished with exit code 1

    一下子就是这么多的都不东西,真的是很揪心。全是bug

     

    import ssl
    ssl._create_default_https_context = ssl._create_unverified_context

     

     

     

    展开全文
  • Conference Call流程介绍

    千次阅读 2020-04-24 10:21:52
    1.Conference call 基本介绍 Conference call 就是常说的电话会议,简单的说就是多台设备同时参与某一路通话(假设为A,B,C三台设备),不是常见的两方对话。详细的解释可以查看:...

    1.Conference call 基本介绍

        Conference call 就是常说的电话会议,简单的说就是多台设备同时参与某一路通话(假设为A,B,C三台设备),不是常见的两方对话。详细的解释可以查看:https://en.wikipedia.org/wiki/Conference_call. 在多方的参与者中,有一方作为host(A),它是这通呼叫的发起方,可以manager这路conference call(与运营商相关). 其他的参与者(B,C)则叫peer call,这两个参与者没有操作这路conference call的能力。

        Conference call 业务是依赖与运营商的,有些运营商是不支持conference call的,在国内暂时只有CMCC支持conference call。发起Conference call有两种方式:1.将两通call merge成conference。这种方式是最为常见的,A拨打一通电话给B,等B接通后,A再拨打一通电话给C,C再接通后,A就可以将这两通电话merge成一通。2.直接拨打conference。这种方式比较少见,应该是只有在ims的情况下才支持(此处不是很确定,在非IMS的情况下我没有见过能够直接拨打conference。A直接输入B&C的号码直接发起conference call.

         在非IMS Conference call 最多包含6个参与者(包括host),当增加到6方通话后,则不允许继续添加参与者了,但是IMS conference 就没有限制。在GSM情况下,几个参与者组成了一通conference call,host 可以管理这路电话,可以将某个参与者踢出(split)这通conference call. 但是在CDMA情况下,host就没有这个能力了。在注册了IMS的情况下,拨打了一个conference call后(A,B,C),会创建一个conference room,然后A,B,C会依次加入这个conferece room中。在A,B,C均加入这个conference room后,及时非host主动挂断电话(C挂断,AB仍然在通过中),此时AB的通话仍然是conference call.

       Conference call成功后,peer call端(B,C)会在InCallUI上显示host(A)的号码,但是在A端只会显示"Conference call"而不会显示B&C的号码。如果有些运营商有特殊要求(SKT),则可以通过解析sip消息来获取B&C的号码。

    2.Conference call 命令下发

       对于conference call,常见的发起方式就是第一种:将两通call merge成conference。下面主要也是解释该流程。Conference call 发起主要可以看作两步:发起两通call & merge两通call.

        发起两通call

    发起两通call的流程,没有特殊的流程,不管是MO或是MT都是可以的。只要A有两通电话就可以了。我本地的做的测试时发起的两通MO call。这步没有什么特殊的地方,主要的log逻辑如下:


    对于A来说现在已经有了两通MO call了,其中一通call为holding,另外一通为active.

        merge两通call

        如果A手机的simcard开通了conference call的业务,那么在InCallUI上就会有merge的button.点击这个merge button,就可以将这两通单独的call merge成conference。

       点击mergebutton,CallButtonPresenter.java# mergeClicked会相应该click事件。
    
          packages/apps/Dialer/java/com/android/incallui/CallButtonPresenter.java
          @Override
          public void mergeClicked() {
            Logger.get(context)
                .logCallImpression(
                    DialerImpression.Type.IN_CALL_MERGE_BUTTON_PRESSED,
                    call.getUniqueCallId(),
                    call.getTimeAddedMs());
            TelecomAdapter.getInstance().merge(call.getId());
          }

     

     packages/apps/Dialer/java/com/android/incallui/call/TelecomAdapter.java
          public void merge(String callId) {
            android.telecom.Call call = getTelecomCallById(callId);
            if (call != null) {
              List<android.telecom.Call> conferenceable = call.getConferenceableCalls();
            /**
             * Returns the list of {@code Call}s with which this {@code Call} is allowed to
             * conference.
             * @ conferenceable.isEmpty The list of conferenceable {@code Call}s.
             */
              if (!conferenceable.isEmpty()) {
                // conferenceable.get(0) --> 被merge的那通call
                call.conference(conferenceable.get(0));
                // It's safe to clear restrict count for merge action.
                DialerCall.clearRestrictedCount();
              } else {
                if (call.getDetails().can(android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE)) {
                  call.mergeConference();
                  // It's safe to clear restrict count for merge action.
                  DialerCall.clearRestrictedCount();
                }
              }
            } else {
              LogUtil.e("TelecomAdapter.merge", "call not in call list " + callId);
            }

    此处要注意的是在执行mergeClicked时,往外传递了一个参数call.getId(),这个Call是当前active 的DialerCall对象。然后在TelecomAdapter通过这个CallId来获取android.telecom.Call对象,并进行merge操作。后续的操作比较简单,没有特别的地方与dial方法类似类似,通过IInCallAdapter来操作Call对象.大概的传递如下:

    Call.java # conference --> InCallAdapter.java # conference

    --> InCallAdapter.java # conference --> CallsManager.java # conference --> Call.java # conferenceWith

    从代码可以到,当执行到这里时,两通需要merge的call已经确定下来。

    /packages/services/Telecomm/src/com/android/server/telecom/Call.java
    void conferenceWith(Call otherCall) {
                if (mConnectionService == null) {
                    Log.w(this, "conference requested on a call without a connection service.");
                } else {
                    Log.addEvent(this, LogUtils.Events.CONFERENCE_WITH, otherCall);
                    mConnectionService.conference(this, otherCall);
                }
            }

    后续的调用逻辑没有太复杂也没有写特别需要注意的地方,与MO call类似,大概的调用逻辑如下:

    ConnectionServiceWrapper.java # conference --> ConnectionServiceWrapper.java # conference
    --> ConnectionService.java # conference # MSG_CONFERENCE # conference # onConference
    --> TelephonyConnectionService.java # onConference # performConference
    --> TelephonyConnection.java # performConference
    --> IMSphone.java # conference()
    --> ImsPhoneCallTracker.java # conference
    --> ImsCall.java # merge
    --> ImsCallSession.java # merge()
    --> ImsCallSessionImpl.java # merge
    --> ImsServiceClassTracker.java # sendConferenceRequest
    --> ImsServiceSub.java # sendConferenceRequest
    --> ImsSenderRxr.java # processSolicited

    由于我是用的product产品打的log,所以这块log不是很多,主要的log逻辑如下:

    在此处需要重点注意的是,当ImsSenderRxr下发了CONFERENCE后,Modem后面会上报三通Call.从log中也可以看出,前两通就是之前分别A打给B,A打给C的电话,属于normalcall,但是第三通call是重新创建的一通Conference call.


    3.Conference call 过程

    在第二步中,Tele已经成功的将conference 命令发给Modem,在等待Modem返回前,上层需要做一些准备,从而来为接下来modem的返回做准备。这块代码没有很复杂,基本都是在vendor/qcom下面实现的,主要通过UNSOL_RESPONSE_CALL_STATE_CHANGED 和 UNSOL_REFRESH_CONF_INFO 来推动的。下面通过log来分步解释下业务逻辑:

     1.modem告知当前两通call 状态发生变化,然后让上层开始处理这些变化,基本没有太多的逻辑变化,与正常的通话相同,有需  注意一点的是此时两通call的状态都是holding状态。

     2.modem再次告知call 状态发生变化。此处需要注意的是,此时多了一通call,而且是一通conference call.然后为这通conference call创建对于的callSession。

                                                                     

    3.当为第三通call创建了对应的callsession等完毕后,除了第三通call是一通conf外,与其他两通call暂时没有区别。需要注意的是,虽然此时modem上报了三通call,但第三通call并没有传递到上层,即在UI上并没有暂时还没有显示这通call.                              

    4.如开头所说,ims conference call会创建一个conference room.然后会将多方通话依次加到conference room.从下面的log中可以看到,这次已经将第一个和第二个参与者加入到conference room 中。而且merge的信息中可以看到参与者的号码(我在log避免号码泄露,将自己的号码改成了xxxx).

    5.当一通电话的参与者已经进入了conference room,那么就没有必要再去维护第一通电话了。所以第一通电话就会被end。

    6.第二通电话参与者加入到conference room,加入成功后会将第二通电话end掉。至此,所有参与者都已经成功的加入了conference room中了,所以modem已经处理完毕了,返回response.


     

    4.处理Modem response

    当modem告知conference 成功后,modem返回个conference 的response.此处处理与正常流程相同。其最终的处理逻辑在
    vendor/qcom/proprietary/telephony-apps/ims/src/org/codeaurora/ims/ImsServiceClassTracker.java

    /**
             * We have detected that a initial conference call has been fully configured. The internal
             * state of both {@code ImsCall} objects need to be cleaned up to reflect the new state.
             * This function should only be called in the context of the merge host to simplify logic
             *
             */
            private void processMergeComplete() {
         
                synchronized(ImsCall.this) {
                    if (isMultiparty()) {
                        ...             
                    } else {                
                        ...
                        if (isSessionAlive(mSession) && !isSessionAlive(mMergePeer.getCallSession())) {            
                         ...
                        } else if (!isSessionAlive(mSession) &&
                                        isSessionAlive(mMergePeer.getCallSession())) {
                         ...
                        } else {
                            // Handles case 1 explained in callSessionMergeComplete
                            // The transient session stays with us and the disconnect sound should not be
                            // played when we ripple up the disconnect for the merge peer because it was
                            // only disconnected to be added to the conference.
                            finalHostCall = this;
                            finalPeerCall = mMergePeer;
                            mMergePeer.markCallAsMerged(false);
                            swapRequired = false;
                            setIsMerged(false);
                            mMergePeer.setIsMerged(true);
                            if (CONF_DBG) {
                                logi("processMergeComplete :: transient will stay with us (I'm the host).");
                            }
                        }
         
                        if (CONF_DBG) {
                            logi("processMergeComplete :: call=" + finalHostCall + " is the final host");
                        }
         
                        // Add the transient session to the ImsCall that ended up being the host for the
                        // conference.
                        finalHostCall.setTransientSessionAsPrimary(transientConferenceSession);
                    }
                    ...
                }
                if (listener != null) {
                    try {
                        // finalPeerCall will have the participant that was not merged and
                        // it will be held state
                        // if peer was merged successfully, finalPeerCall will be null
                        listener.onCallMerged(finalHostCall, finalPeerCall, swapRequired);
                    } catch (Throwable t) {
                        loge("processMergeComplete :: ", t);
                    }
                    if (mConferenceParticipants != null && !mConferenceParticipants.isEmpty()) {
                        try {
                            listener.onConferenceParticipantsStateChanged(finalHostCall,
                                    mConferenceParticipants);
                        } catch (Throwable t) {
                            loge("processMergeComplete :: ", t);
                        }
                    }
                }
                return;
            }

    1.高通的IMS模块将这些conference 的信息传递给Tele-FW,IMSCall处理上报的信息,确认Host,更改multiparty状态等,主要log如下:

    2.依次为参与者创建conference的connection,并以此connection创建对应的call对象。    

                                                 
     3.后面两个参与者创建方式与第一次相同

                                                                
    4.将新创建的三个call设置成conference call的child.

    5.创建对应的DialerCall,并且end掉之前的两通(A-B,A-C)Dialer。

     至此,Conference 的整个过程就全部完成了。


     5.总结--各种Call对象的转换

       此篇分析完全是根据log & 代码来看的,肯定有些错误的地方,后期发现会来更改。我对conference call的理解,比较混乱就是各个call对象,而且各种转换,以至于到最后在Dialer里面有4个call对象。所以单独把这快拎出来总结下:

    *在A拨号给B时,属于正常的拨号,所以都是正常的一个;
    *在A拨号给C时,也是正常的拨号,所以都是正常的两个;


    *在3.2时,由于已经发起了conference,modem会上报一个conference call.这通conferencall 暂时是一通不带任何信息的call.        * 其实可以把这通conference call想象成一通可接入的room,后期merge的过程,是各个参与者(A,B,C)分别接入这个room中,可以想象成A,B,C分别拨给conference room;


    *在3.5 & 3.5时,A ,B,C分别merge了,所以ims需要维护的就越来越少,最终只需要维护一通conferen 就够了。
    *在4.2时,分别通过participant 的connection 创建了对应的三通Telecom call ,而且此时还未end 之前A->B & A->C的call.        
    *在4.5时,整体merge完成,ims 就一通conference call,其他都是4通call.这4通call可以理解成:conference call 1通,A 拨给conference room 的1通,B拨给conference room 的1通,C拨给conference room 的1通。

    展开全文
  • Retrofit之OkhttpCall执行原理详解

    千次阅读 2018-09-08 19:48:25
    根据《Retrofit源码解析之请求流程概述》我们知道Retrofit通过OkhttpCall来完成同步或者异步请求,那么OkhttpCall的execute和enqueue方法是什么时候开始执行的呢?这篇博文就来简单的扒一扒其内部原理。...

    根据《Retrofit源码解析之请求流程概述》我们知道Retrofit通过OkhttpCall来完成同步或者异步请求,那么OkhttpCall的execute和enqueue方法是什么时候开始执行的呢?这篇博文就来简单的扒一扒其内部原理。

    简单以Retrofit同步请求作为说明,简单的例子如下:

    interface MyApi {
      @Get
      Call<YourBean> getData(params)
    }
    
    MyApi mApi = retrofit.create(MyApi.class);
    
    Call<YourBean> testCall= mApi.getData(params);
    
    //*发送网络请求(同步)
    Response<YourBean> response = testCall.execute();
    
    //获取数据
    YourBean bean = response.body();

    用法很简单,就是先调用Retrofit的create方法获取一个MyApi对象,然后执行某一个getData方法返回一个Call对象,那么这个Call对象会是OkhttpCall吗?答案是No! 下面就抽丝剥茧来分析下这个Call对象是神马牛鬼蛇神。


    先来看看Retrofit的create方法:

    public <T> T create(final Class<T> service) {
        //省略与本文无关的代码
        return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
            new InvocationHandler() {
              private final Platform platform = Platform.get();
    
              @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
                  throws Throwable {
                 //省略无关代码
    
                ServiceMethod<Object, Object> serviceMethod =
                    (ServiceMethod<Object, Object>) loadServiceMethod(method);
                OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
                return serviceMethod.adapt(okHttpCall);
              }
            });
      }

    create方法的入参是一个Interface的Class对象,但是返回的是一个Proxy.newProxyInstance代理对象,因为我们在使用Retrofit的时候只需要定义API接口及其对应的方法,而不需要自己implements API interface.但是接口的方法是用来执行的,你不实现接口怎么能执行呢?代理对象的强大之处就体现出来了:
    只需要根据你传入的接口,生成一个代理对象,之后所有的方法调用都会走代理对象invoke方法;且代理对象不需要关心你具体执行方法的名字,一律以method表示. InvocationHandler接口只有一个方法,即invoke()方法!它是对代理对象所有方法的唯一实现。也就是说,无论你调用代理对象上的哪个方法,其实都是在调用InvocationHandler的invoke()方法。我们只需要invoke对Method和args进行处理即可。

    可以说Retrofit就是利用代理对象的这一特性,将网络框架的使用简易化:

    因为API接口所有方法调用的目的就是把方法的注解信息以及参数信息进行扫描和解析,交给OkhttpCall进行处理执行网络调用

    ,既然所有的API接口方法调用都是基于同一目的,那么全部就交给代理对象代劳就是了,代理的强大之处被利用的淋漓尽致。

    啰嗦了这么多,下面就来看看其invoke方法都做了啥:

     //根据你调用的某个method,调用loadServiceMethod方法。获取对应的ServiceMthod对象
     ServiceMethod<Object, Object> serviceMethod =
                    (ServiceMethod<Object, Object>) loadServiceMethod(method);
      //将参数和Service构成一个OkhttpCall对象              
      OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
    
    //数据返回  
    return serviceMethod.adapt(okHttpCall);

    步骤很简单明了:
    1、根据你调用某个方法method对象从缓存中获取对应的ServiceMethod对象,如果缓存没有则创建一个。
    2、将method对应的serviceMethod及其参数args,初始化一个OkHttpCall对象
    3、执行serviceMethod的adapt方法,返回一个Call


    ServiceMthod的创建

    先看看serviceMethod是怎么创建的:

    ServiceMethod<?, ?> loadServiceMethod(Method method) {
        ServiceMethod<?, ?> result = serviceMethodCache.get(method);
        //缓存中有则使用缓存里面的
        if (result != null) return result;
    
        synchronized (serviceMethodCache) {
          result = serviceMethodCache.get(method);
          if (result == null) {
            //没有缓存则创建一个ServiceMethod
            //this是Retrofit
            result = new ServiceMethod.Builder<>(this, method).build();
            serviceMethodCache.put(method, result);
          }
        }
        return result;
      }

    看看ServieMethod.Builder方法都有啥:

     Builder(Retrofit retrofit, Method method) {
          this.retrofit = retrofit;
          this.method = method;
          //获取Api某个方法的注解信息
          this.methodAnnotations = method.getAnnotations();
    
          //*这个解释有点绕,看https://blog.csdn.net/jiang_bing/article/details/7794365
          this.parameterTypes = method.getGenericParameterTypes();
          //获取参数的注解信息
          this.parameterAnnotationsArray = method.getParameterAnnotations();
        }

    从上面代码可以看出,Builder的构造器的作用就是拿到一个Method对应的信息,比如方法注解信息,参数注解信息等,然后再来看看Buider的build方法:

    CallAdapter<T, R> callAdapter;
    
    public ServiceMethod build() {
          //创建一个callAdapter
          callAdapter = createCallAdapter();
          //获取方法的返回类型
          responseType = callAdapter.responseType();
    
          if (responseType == Response.class || responseType == okhttp3.Response.class) {
            throw methodError("'"
                + Utils.getRawType(responseType).getName()
                + "' is not a valid response body type. Did you mean ResponseBody?");
          }
          //根据returnType创建数据转换器 
          responseConverter = createResponseConverter();
    
          //解析方法注解
          for (Annotation annotation : methodAnnotations) {
            parseMethodAnnotation(annotation);
          }
          //省略部分注解处理代码:详细解析会另外开启博文说明
    
          return new ServiceMethod<>(this);
        }
    

    CallAdapter方法简单说明
    build方法的第一个步骤就是createCallAdapter()创建一个callAdapter,还记得上面代理对象的invoke方法最后一行吗?即return serviceMthod.adapt(OkhttpCall),内部就是调用了callAdapter的adapt方法:

     T adapt(Call<R> call) {
        return callAdapter.adapt(call);
      }

    所以继续瞅瞅createCallAdapter都干了啥:

     private CallAdapter<T, R> createCallAdapter() {
          //得到目标方法返回类型对应的Type对象
          Type returnType = method.getGenericReturnType();
    
          //获取方法的注解信息
          Annotation[] annotations = method.getAnnotations();
          //根据热天run
            return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
          }
        }
    

    至于返回哪一个CallAdapter,为了博文的条理性,在这里先直接说结论:
    返回是CallAdapte是由从Anrdoid Platfom的ExecutorCallAdapterFactory工厂对象生成的

    static class Android extends Platform {
        @Override public Executor defaultCallbackExecutor() {
          return new MainThreadExecutor();
        }
    
        @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
          //此处的callbackExecutor就是MainThreadExecutor
          return new ExecutorCallAdapterFactory(callbackExecutor);
        }
    
        static class MainThreadExecutor implements Executor {
          private final Handler handler = new Handler(Looper.getMainLooper());
    
          @Override public void execute(Runnable r) {
            //使用handle来post一个任务
            handler.post(r);
          }
        }
      }

    ExecutorCallAdapterFactory工厂对象持有一个MainThreadExecutor ,该MainThreadExecutor的作用是将一个任务Runnable都通过handle发送到Android消息队列中去执行

    进而看看这个工厂对象返回的CallAdapter是神马:

      @Override
      public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
        //method方法返回值类型必须是Call
        if (getRawType(returnType) != Call.class) {
          return null;
        }
        //获取Call<T>的泛型T的类型
        final Type responseType = Utils.getCallResponseType(returnType);
    
        return new CallAdapter<Object, Call<?>>() {
          @Override public Type responseType() {
            //Call<JavaBean>那么返回的就是JavaBean
            return responseType;
          }
          //最终invoke会执行的方法
          //adapt方法参数的call就是OKhttpCall
          @Override public Call<Object> adapt(Call<Object> call) {
            //callbackExecutor是MainThreadExecutor 
            return new ExecutorCallbackCall<>(callbackExecutor, call);
          }
        };
      }

    上述get方法有几个要注意的地方:
    1、Api Service定义的方法的返回值必须是Call《T》类型(当然这是没有结合rx使用的情况)
    2、CallAdapter的responseType()方法返回的就是对应的JavaBean的类型,正如注释所说:For example, the response type for {@code Call<Repo>} is {@code Repo}
    3、最终CallAdapter的adapt返回的就是ExecutorCallbackCall,而adapt的方法参数就是我们的OKhttpCall(参见文章开头对invoke方法的说明)。也即是说下面的代码中的Call就是ExecutorCallbackCall:

    /*实际上返回的就是ExecutorCallbackCall*/
    Call<T> call= Api.getData();
    Resonse<T> response = call.execute();
    T data = response.body();

    4、ExecutorCallbackCall持有的callbackExecutor引用指向的对象就是MainThreadExecutor

     final class ExecutorCallbackCall<T> implements Call<T>{
        //MainThreadExecutor 
        final Executor callbackExecutor;
        //OKhttpCall
        final Call<T> delegate;
    
        ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
          this.callbackExecutor = callbackExecutor;
          this.delegate = delegate;
        }
     }
    

    所以文章开头testCall.execute()执行的就是ExecutorCallbackCall的execute方法,而该方法又是代理给OkhttpCall的execute方法:

    //同步网络请求
     public Response<T> execute() throws IOException {
          //OkhttpCall真正执行的地方
          return delegate.execute();
        }

    那么在看看其异步网络请求:

     public void enqueue(final Callback<T> callback) {
          //同样执行的是OKhttpCall的enqueue方法
          delegate.enqueue(new Callback<T>() {
            @Override public void onResponse(Call<T> call, final Response<T> response) {
              callbackExecutor.execute(new Runnable() {
                @Override public void run() {
                  if (delegate.isCanceled()) {//请求取消
                    callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
                  } else {
                    //请求成功
                    callback.onResponse(ExecutorCallbackCall.this, response);
                  }
                }
              });
            }
    
             //网络请求失败
            @Override public void onFailure(Call<T> call, final Throwable t) {
              callbackExecutor.execute(new Runnable() {
                @Override public void run() {
                  callback.onFailure(ExecutorCallbackCall.this, t);
                }
              });
            }
          });
        }

    异步请求其实也很简单,其内部就是调用了OkhttpCall的enqueue,只不过在回调结果的时候通过MainThreadExecutor转到了UI线程中去处理了。

    到此为止OkttpCall的执行讲解完毕,代码其实很绕,分析其源码的时候各种方法来回跳转,很容易混乱。比如这个OkhttpCall可以直接返回,但是层层代码各种传递才能分析出invoke返回的Call是个什么玩意。为什么本来简单的调用要搞这么复杂呢?这个问题会从代码设计的绝对另开博客详细说明。

    总结下来就是:
    某ApiService定义的一系烈方法中,你调用了几个个方法,就会对应创建几个ServiceMethod对象,同时也会对应创建几个OkhttpCall来执行。

    最后以一个流程图来完成做结:
    这里写图片描述

    展开全文
  • call(zoom)_如何解决您的Zoom Call问题

    千次阅读 2020-09-20 18:04:22
    call(zoom)A lot of people and businesses have turned to Zoom as their go-to video-conferencing application. However, Zoom isn’t always perfect. Here are some tips on troubleshooting your Zoom call ...
    call(zoom)

    call(zoom)

    Zoom Logo

    A lot of people and businesses have turned to Zoom as their go-to video-conferencing application. However, Zoom isn’t always perfect. Here are some tips on troubleshooting your Zoom call for a better audio and video call experience.

    许多人和企业已经将Zoom用作其视频会议应用程序。 但是,缩放并不总是完美的。 以下是一些有关对Zoom呼叫进行故障排除的提示,以获取更好的音频和视频通话体验。

    查看系统要求 (Review System Requirements)

    When running any type of software, one of the first things you need to do is check that your device is up to the task. No matter if everything is installed and set up properly, if you’re using old and outdated hardware or hardware that doesn’t meet the minimum requirements, it’s not going to run smoothly.

    在运行任何类型的软件时,您需要做的第一件事就是检查设备是否能够胜任该任务。 无论是否正确安装和设置了所有组件,如果您使用的是过时的旧硬件或不满足最低要求的硬件,它都将无法流畅运行。

    Zoom conveniently lists out the requirements, from system requirements, to supported operating systems and browsers, to supported devices. Give it a read and make sure your device is up to the task.

    Zoom方便地列出了需求 ,从系统需求到支持的操作系统和浏览器,再到支持的设备。 对其进行阅读,并确保您的设备能够完成任务。

    检查您的网络 (Check Your Network)

    Unsurprisingly, you also need to have a decent internet connection to use video conferencing apps. Zoom lists out those requirements for you as well. We’ll give you the short version here. These are the minimum requirements only. It’s better if you can exceed these numbers:

    毫不奇怪,您还需要具有良好的Internet连接才能使用视频会议应用程序。 Zoom也为您列出了这些要求 。 我们在这里给您简短的版本。 这些仅是最低要求。 最好能超过这些数字:

    • High-quality 1-on-1 video chat: 600kbps up/down

      高质量的一对一视频聊天:上/下600kbps
    • High-quality group video chat: 800kbps upload, 1Mbps download

      高质量的团体视频聊天:800kbps上传,1Mbps下载
    • Screensharing:

      屏幕共享:

      • With video thumbnail: 50-150kbps

        带有视频缩略图:50-150kbps
      • Without video thumbnail: 50-75kbps

        不带视频缩略图:50-75kbps

    You can check your internet speed online using Speedtest. Just head over to the site and select “Go.”

    您可以使用Speedtest在线检查互联网速度。 只需转到该站点,然后选择“开始”即可。

    Go button on the speedtest site

    After a few moments, you’ll get the latency (ping), download, and upload speed results.

    片刻之后,您将获得延迟(ping),下载和上传速度结果。

    Results of the speed test

    Cross-check your results with Zoom’s requirements to see if your network speed is the source of your Zoom problems.

    将结果与Zoom的要求交叉检查,以查看网络速度是否是Zoom问题的根源。

    If you do meet the network requirements and are having issues, it could be that you need to tweak some Zoom settings.

    如果您确实满足网络要求并且遇到问题,则可能是需要调整某些“缩放”设置。

    调整缩放设置以提高性能 (Adjust Your Zoom Settings to Improve Performance)

    We mentioned the minimum requirements in the previous section, but that’s only the minimum requirements to be able to use a Zoom call. If you barely meet those requirements but have some other features enabled, then the minimum requirements are going to increase and it’s possible you don’t meet them anymore.

    我们在上一节中提到了最低要求,但这只是能够使用Zoom调用的最低要求。 如果您几乎不满足这些要求,但启用了其他一些功能,那么最低要求将会增加,并且您可能不再满足这些要求。

    Two of the main features you should disable are “HD” and “Touch Up My Appearance.” We all want to look nice on a Zoom call, but there are other ways. We actually give some tips on looking your best in a Zoom call. Disable these two settings and give that article a read to look great while retaining network speed.

    您应禁用的两个主要功能是“高清”和“润饰我的外观”。 我们都希望在Zoom通话中看起来不错,但是还有其他方法。 实际上,我们给出了一些有关在Zoom呼叫中表现最佳的提示。 禁用这两个设置,并在保持网络速度的同时使该文章看起来不错。

    To disable these settings, open your Zoom client, then select the “Gear” icon in the top-right corner to open the “Settings” menu.

    要禁用这些设置,请打开您的Zoom客户端,然后选择右上角的“齿轮”图标以打开“设置”菜单。

    Gear icon in Zoom client

    Select “Video” in the left-hand pane.

    在左侧窗格中选择“视频”。

    Video option in left-hand pane

    In the “My Video” section, uncheck the boxes next to (1) “Enable HD” and (2) “Touch Up My Appearance.”

    在“我的视频”部分中,取消选中(1)“启用高清”和(2)“润色我的外观”旁边的框。

    Enable HD and touch up my appearance options in Zoom

    If your video feed isn’t really required for the call, you can also turn it off completely.

    如果通话实际上并不需要您的视频供稿,也可以将其完全关闭。

    解决音频回声/反馈问题 (Fixing the Audio Echo/Feedback Issue)

    Audio echo is a common problem people tend to experience with video conferencing software. Echo also includes that really loud screech (i.e., audio feedback) that’s worse than nails on a chalkboard. Here are a few common causes of this issue:

    音频回声是人们通常会在视频会议软件上遇到的常见问题。 回声还包括比黑板上的钉子还糟糕的声音(例如声音反馈)。 以下是此问题的一些常见原因:

    • Multiple devices with the audio turned on in the same room

      多个设备在同一房间中打开了音频
    • One participant with the computer and phone audio both turned on

      一位参与者同时打开了计算机和电话音频
    • Participants have their computers or speakers too close

      参加者的电脑或扬声器离得太近

    Make sure you stay spread out if you share a conference room with another attendee, and if you’re not speaking set your mic on mute. We also recommend using headphones when possible.

    如果您与其他与会者共享会议室,并且不讲话,请确保您保持分散状态。 我们还建议尽可能使用耳机。

    您的视频没有显示 (Your Video Isn’t Showing)

    This can be caused by several issues. First and foremost, check that your video is actually turned on. During the Zoom call, you’ll know your video is off if the camcorder icon in the bottom-left corner has a red slash through it. Click the “Camcorder” icon to turn on your video.

    这可能是由几个问题引起的。 首先,请检查您的视频是否已打开。 在Zoom通话期间,如果左下角的摄录机图标上有一个红色斜线,您将知道视频已关闭。 单击“摄像机”图标以打开视频。

    Start video button on Zoom call

    Also, make sure that you have the correct camera selected. To see which camera Zoom is currently using, select the arrow next to the camcorder icon and your currently-in-use camera will be displayed. If that’s not the one you’re looking for, you can select the correct one from this menu (if you have other cameras connected, that is), or you can do so in the Settings menu by clicking the “Gear” icon and then selecting “Video Settings.”

    另外,请确保选择了正确的摄像机。 要查看Zoom当前正在使用哪个摄像机,请选择摄像机图标旁边的箭头,然后将显示您当前正在使用的摄像机。 如果不是您要查找的那个,则可以从此菜单中选择正确的一个(如果您连接了其他摄像机),也可以在“设置”菜单中单击“齿轮”图标,然后选择选择“视频设置”。

    Video settings in call

    In the “Camera” section, select the arrow and choose your camera from the menu.

    在“摄像机”部分中,选择箭头,然后从菜单中选择您的摄像机。

    Select the camera in the settings menu

    Additionally, make sure that no other program on your device is currently using the camera. If so, close that program. This could fix the issue.

    此外,请确保设备上当前没有其他程序在使用相机。 如果是这样,请关闭该程序。 这可以解决问题。

    It’s also a good idea to make sure you’ve updated the camera driver to the latest version. You can generally do this from the camera manufacturer’s download and support page on its official website.

    确保已将相机驱动程序更新到最新版本也是一个好主意。 通常,您可以从相机制造商的官方网站上的下载和支持页面进行此操作。

    If all else fails, restart your computer and try again. If your video still isn’t working, it could be an issue with the webcam itself. Contact the manufacturer’s support team.

    如果其他所有方法均失败,请重新启动计算机,然后重试。 如果您的视频仍然无法正常播放,则可能是网络摄像头本身存在问题。 请与制造商的支持团队联系。

    联系Zoom的支持团队 (Contact Zoom’s Support Team)

    Word on the street is Zoom has a pretty good team of support members. If you can’t figure out what’s going on with Zoom, it’s always a good idea to contact the experts.

    在大街上可以说的是Zoom拥有一支相当不错的支持人员团队。 如果您不知道Zoom发生了什么,最好与专家联系。

    If they aren’t able to fix the issue with you right away, Zoom support can actually send you a troubleshooting package to store log files. Once you’ve installed this package, you can zip the log files and send it over to the support team for further analysis. The company provides instructions on how to do this for Windows 10 PC, Mac, and Linux on its Support page.

    如果他们不能立即解决您的问题,Zoom支持人员实际上可以向您发送故障排除程序包来存储日志文件。 安装此软件包后,您可以压缩日志文件并将其发送给支持团队以进行进一步分析。 该公司在其“支持”页面上提供了针对Windows 10 PCMacLinux的操作说明。

    翻译自: https://www.howtogeek.com/676235/how-to-troubleshoot-your-zoom-call/

    call(zoom)

    展开全文
  • 在使用tensorflow低阶API实现线性回归时,模型如下定义: ```python class Model(object): def __init__(self): self.w = tf.random.uniform([1]) ...需要将`__call__`修改为`call` 这两者区别是什么?
  • result = PyObject_CallFunction(g_callback, "{s:s, s:i}", "URI", uri, "VALUE", atoi(Val_1)); if (result != NULL) Py_DECREF(result); else DEBUG_PRINTF("PyObject_CallFunction does not work well ! \n...
  • 超级详细找CALLCALL教程[转]

    千次阅读 2019-07-05 01:51:02
    首先我们要知道一点,为什么要找CALLCALL是什么?大家知道易里的子程序吧如何调用子程序的?这里的CALL就是调用子程序的意思,那问了为什么要找他的,答案是:当你些个游戏的外挂用模拟键盘操作的时候,被操作的...
  • Traceback (most recent call last):

    万次阅读 2019-05-12 14:13:15
    |Traceback (most recent call last) EOFError: EOF when reading a line Traceback (most recent call last): File "C:\Users\31368\Desktop\post-1.py", line 24, in <module> response=urllib.reques...
  • 独立团CALL测试工具,找CALL必备,写挂工具,逆向工程
  • 深挖call的底层实现原理 在js中有3个方法可以改变函数中this的指向,那就是call、apply和bind。关于三个方法的更多详细请参考web前端高级 - JavaScript中函数内的this指向。这里只讲一下call的底层实现原理。下面来...
  • RocketMQ的invokeSync call timeout异常的解决办法

    千次阅读 多人点赞 2021-07-27 15:33:15
    在RocketMQ客户端的DefaultMQPushConsumer的start方法被执行时,时不时会报出invokeSync call timeout异常,如下: Caused by: java.lang.IllegalStateException: org.apache.rocketmq.remoting.exception....
  • 目录 1 函数的定义方式 1.1 函数声明 ...4.1.1 新的函数调用方式apply和call方法 4.1.2 apply和call可以改变this的指向 4.2 call,apply使用 4.3 bind 4.4 总结 5 函数的其它成员(了解) 6
  • E-Call、B-Call、I-Call

    千次阅读 2020-11-23 19:20:00
    在网联通讯中,主机系统不仅可以链接蓝牙电话,还支持ECall / BCall / ICall 功能。下面简单介绍下会遇到的常用名词: TBox 是汽车网络通讯的重要部件,一个带通讯功能的盒子,内含一张SIM卡,配套硬件还有GPS天线、...
  • Conference Call在项目中的场景不是很多,在日常生活应用也不是很多,基本上项目上的需求原生的代码已经足够。我所接触的只是之前在一个STK 运营商项目上时,对Conference call 有很多UI &amp; 功能的要求,所以...
  • MetaException(message:org.apache.hadoop.hbase.client....Wed Sep 09 23:45:02 CST 2020, null, java.net.SocketTimeoutException: callTimeout=60000, callDuration=68720: row 'xyz,,' on table 'hbase:me
  • resource failed to call close

    千次阅读 2021-05-26 11:27:30
    在运行Android项目时,日志中会出现A resource failed to call close告警信息: 2021-05-26 11:26:52.564 11386-11401/com.xxx.example W/System: A resource failed to call close. 这是由于文件输入和输出流在...
  • call和apply的使用

    千次阅读 多人点赞 2018-06-05 15:48:26
    就是想整理一篇关于call和apply的文档,不想编一些什么最近学习的时候遇到问题研究之后想分享给大家之类的理由,就是想写!就是想发!就是想!!!以下是正文&gt;&gt;&gt;&gt;&gt;&gt;&...
  • 游戏Call技术-绑定主线程调用CALL技术(反游戏检测call) 我们在写call调用游戏进程里call时候,经常辅助运行一段时间后,游戏就会断线或崩溃掉,但是经过检查, 发现我们调用CALL的源代码又没发现写错误,这到底是怎样呢...
  • 找游戏关键CALL入门

    千次阅读 2018-09-22 13:03:23
    找游戏关键CALL入门 用OD启动游戏 为了实习找死亡回城函数,大家建个小号,先弄死它 我们转回OD 在OD的左下角可以打入命令 bp send 回车 之后立即回到游戏,点游戏里的&lt;回到附近城市&gt;, 这时OD断在...
  • MO CALL流程

    千次阅读 2017-07-12 19:18:49
    Call文件目录从上层InCallUI一直到Telephony Framework层,总共包含下面五个部分。 InCallUI : packages/apps/InCallUI (system/priv-app/InCallUI.apk) Telecom framwork : Frameworks/base/Telecomm (system/...
  • 我们在写call调用网络游戏进程里call时候,经常外挂辅助程序运行工作一段时间后,网络游戏就会断线或崩溃掉,但是经过检查, 发现自己调用CALL的代码又没发现写错误,这到底是怎么呢?{:100_162:} 其实这些是现在网络...
  • Android Call分析(一) ---- Call对象详解

    万次阅读 多人点赞 2016-09-16 17:46:39
    Call(通话)相关的内容也是属于Telephony模块,Call整体上可以分成两类: 1. CS call,其中CS全称是Circuit Switch,我们平常打电话走的就是CS的流程。 2. IMS PS call,其中PS全称是Packet Switch,走IMS流程的...
  • 一、学习this的指向问题 二、call和apply的特点与区别 三、模拟实现一个call 四、bind的功能 五、结尾 思考题+导图+示例代码,让你轻松掌握!
  • JS call方法原理

    千次阅读 2018-11-15 09:11:30
    前言 本来计划是, 先把深入React技术栈过完,  但是,现在在满足RN app开发情况下,我还是先深入js一个系列。...(一)call源码解析 首先上一个call使用 function add(c, d) {  return this.a + this.b + c...
  • call 测试工具

    热门讨论 2010-01-18 22:18:33
    做外挂的朋友都知道,最关键的不是写代码,而是找游戏关键call,这里有个招call工具,帮助大家快速找到关键call,首先生命,这是引用的别人的。不是我写的。 只为了大家方便。。。
  • VoiceCall流程解析

    千次阅读 2019-05-08 11:30:05
    文章目录概述框架VoiceCall框架图流程相关主要代码介绍VoiceCall相关的基本概念主动呼叫(MO)流程被动接听(MT)流程 本文章代码基于Android 9.0 概述 VoiceCall就是我们通常所说的打电话是基于系统中Telephony...
  • 实际上,可以认为DELEGATECALL是CALLCODE的一个bugfix版本,官方已经不建议使用CALLCODE了。 CALLCODE和DELEGATECALL的区别在于: msg.sender不同 。 具体来说,DELEGATECALL会一直使用原始调用者的地址,而CALL...
  • 易语言远程x64位汇编call技术

    千次阅读 2020-08-23 21:56:06
    易语言x64位调用call函数技术 上两篇易语言对x64位进程操作的技术贴发出后,因为得知我们 Game-Ec 驱动模块8.5.3里 开发了对x64程序进程里的模块,API取地址,内存读写,内存搜索,函数hook,call函数调用等诸多命令...
  • E-Call:当开车如遭遇紧急情况,用户可按下该键以最高优先级接通呼叫中心,人工坐席将同时获取客户车辆的重要数据并协助驾驶员脱离危险,当遇到特殊情况,汽车气囊弹出车辆会发出消息通知Tbox拨打紧急电话。...
  • call、start、goto的区别

    千次阅读 2018-03-23 16:26:27
    一、call命令总结【1】call命令简介 学过汇编或C的朋友,肯定都知道call指令表示什么意思。其实,在这里它的意思也是一样的。在批处理脚本中,call命令用来从一个批处理脚本中调用另一个批处理脚本。 语法: call...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,589,461
精华内容 635,784
关键字:

call