summaryrefslogtreecommitdiffstats
path: root/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp
blob: fa703ab0b8f2c665424ecdb2016de53627c4bffb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "WidevineAdapter.h"
#include "content_decryption_module.h"
#include "VideoUtils.h"
#include "WidevineDecryptor.h"
#include "WidevineUtils.h"
#include "WidevineVideoDecoder.h"
#include "gmp-api/gmp-entrypoints.h"
#include "gmp-api/gmp-decryption.h"
#include "gmp-api/gmp-video-codec.h"
#include "gmp-api/gmp-platform.h"

static const GMPPlatformAPI* sPlatform = nullptr;

namespace mozilla {

GMPErr GMPGetCurrentTime(GMPTimestamp* aOutTime) {
  return sPlatform->getcurrenttime(aOutTime);
}

// Call on main thread only.
GMPErr GMPSetTimerOnMainThread(GMPTask* aTask, int64_t aTimeoutMS) {
  return sPlatform->settimer(aTask, aTimeoutMS);
}

GMPErr GMPCreateRecord(const char* aRecordName,
                       uint32_t aRecordNameSize,
                       GMPRecord** aOutRecord,
                       GMPRecordClient* aClient)
{
  return sPlatform->createrecord(aRecordName, aRecordNameSize, aOutRecord, aClient);
}

void
WidevineAdapter::SetAdaptee(PRLibrary* aLib)
{
  mLib = aLib;
}

void* GetCdmHost(int aHostInterfaceVersion, void* aUserData)
{
  Log("GetCdmHostFunc(%d, %p)", aHostInterfaceVersion, aUserData);
  WidevineDecryptor* decryptor = reinterpret_cast<WidevineDecryptor*>(aUserData);
  MOZ_ASSERT(decryptor);
  return static_cast<cdm::Host_9*>(decryptor);
}

#define STRINGIFY(s) _STRINGIFY(s)
#define _STRINGIFY(s) #s

GMPErr
WidevineAdapter::GMPInit(const GMPPlatformAPI* aPlatformAPI)
{
#ifdef ENABLE_WIDEVINE_LOG
  if (getenv("GMP_LOG_FILE")) {
    // Clear log file.
    FILE* f = fopen(getenv("GMP_LOG_FILE"), "w");
    if (f) {
      fclose(f);
    }
  }
#endif

  sPlatform = aPlatformAPI;
  if (!mLib) {
    return GMPGenericErr;
  }

  auto init = reinterpret_cast<decltype(::INITIALIZE_CDM_MODULE)*>(
    PR_FindFunctionSymbol(mLib, STRINGIFY(INITIALIZE_CDM_MODULE)));
  if (!init) {
    return GMPGenericErr;
  }

  Log(STRINGIFY(INITIALIZE_CDM_MODULE)"()");
  init();

  return GMPNoErr;
}

GMPErr
WidevineAdapter::GMPGetAPI(const char* aAPIName,
                           void* aHostAPI,
                           void** aPluginAPI,
                           uint32_t aDecryptorId)
{
  Log("WidevineAdapter::GMPGetAPI(%s, 0x%p, 0x%p, %u) this=0x%p",
      aAPIName, aHostAPI, aPluginAPI, this, aDecryptorId);
  if (!strcmp(aAPIName, GMP_API_DECRYPTOR)) {
    if (WidevineDecryptor::GetInstance(aDecryptorId)) {
      // We only support one CDM instance per PGMPDecryptor. Fail!
      Log("WidevineAdapter::GMPGetAPI() Tried to create more than once CDM per IPDL actor! FAIL!");
      return GMPQuotaExceededErr;
    }
    auto create = reinterpret_cast<decltype(::CreateCdmInstance)*>(
      PR_FindFunctionSymbol(mLib, "CreateCdmInstance"));
    if (!create) {
      Log("WidevineAdapter::GMPGetAPI(%s, 0x%p, 0x%p, %u) this=0x%p FAILED to find CreateCdmInstance",
        aAPIName, aHostAPI, aPluginAPI, this, aDecryptorId);
      return GMPGenericErr;
    }

    WidevineDecryptor* decryptor = new WidevineDecryptor();

    auto cdm = reinterpret_cast<cdm::ContentDecryptionModule*>(
      create(cdm::ContentDecryptionModule::kVersion,
             kEMEKeySystemWidevine.get(),
             kEMEKeySystemWidevine.Length(),
             &GetCdmHost,
             decryptor));
    if (!cdm) {
      Log("WidevineAdapter::GMPGetAPI(%s, 0x%p, 0x%p, %u) this=0x%p FAILED to create cdm",
          aAPIName, aHostAPI, aPluginAPI, this, aDecryptorId);
      return GMPGenericErr;
    }
    Log("cdm: 0x%x", cdm);
    RefPtr<CDMWrapper> wrapper(new CDMWrapper(cdm, decryptor));
    decryptor->SetCDM(wrapper, aDecryptorId);
    *aPluginAPI = decryptor;

  } else if (!strcmp(aAPIName, GMP_API_VIDEO_DECODER)) {
    RefPtr<CDMWrapper> wrapper = WidevineDecryptor::GetInstance(aDecryptorId);
    if (!wrapper) {
      Log("WidevineAdapter::GMPGetAPI(%s, 0x%p, 0x%p, %u) this=0x%p No cdm for video decoder",
          aAPIName, aHostAPI, aPluginAPI, thiss, aDecryptorId);
      return GMPGenericErr;
    }
    *aPluginAPI = new WidevineVideoDecoder(static_cast<GMPVideoHost*>(aHostAPI),
                                           wrapper);
  }
  return *aPluginAPI ? GMPNoErr : GMPNotImplementedErr;
}

void
WidevineAdapter::GMPShutdown()
{
  Log("WidevineAdapter::GMPShutdown()");

  decltype(::DeinitializeCdmModule)* deinit;
  deinit = (decltype(deinit))(PR_FindFunctionSymbol(mLib, "DeinitializeCdmModule"));
  if (deinit) {
    Log("DeinitializeCdmModule()");
    deinit();
  }
}

void
WidevineAdapter::GMPSetNodeId(const char* aNodeId, uint32_t aLength)
{

}

/* static */
bool
WidevineAdapter::Supports(int32_t aModuleVersion,
                          int32_t aInterfaceVersion,
                          int32_t aHostVersion)
{
  return aModuleVersion == CDM_MODULE_VERSION &&
         aInterfaceVersion == cdm::ContentDecryptionModule::kVersion &&
         aHostVersion == cdm::Host_9::kVersion;
}

} // namespace mozilla