or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

analytics.mdaudio-rendering.mdcore-player.mddrm-support.mdindex.mdmedia-sources.mdoffline-support.mdtrack-selection.mdvideo-rendering.md

drm-support.mddocs/

0

# DRM Support

1

2

ExoPlayer provides comprehensive Digital Rights Management (DRM) support for protected content playback. The DRM system handles key acquisition, session management, and secure decoding for various DRM schemes including Widevine, PlayReady, and ClearKey.

3

4

## DrmSessionManager Interface

5

6

The core interface for managing DRM sessions and cryptographic operations.

7

8

```java { .api }

9

public interface DrmSessionManager {

10

/**

11

* Prepares the DRM session manager.

12

*/

13

void prepare();

14

15

/**

16

* Returns the crypto type for the given format.

17

*

18

* @param format The format

19

* @return The crypto type, or C.CRYPTO_TYPE_NONE if not encrypted

20

*/

21

@C.CryptoType int getCryptoType(Format format);

22

23

/**

24

* Acquires a DRM session for the given DRM init data.

25

*

26

* @param playbackLooper The playback looper

27

* @param drmInitData The DRM initialization data

28

* @return The DRM session

29

*/

30

@Nullable DrmSession acquireSession(@Nullable Looper playbackLooper, @Nullable DrmInitData drmInitData);

31

32

/**

33

* Releases a DRM session.

34

*

35

* @param drmSession The session to release

36

*/

37

void releaseSession(@Nullable DrmSession drmSession);

38

39

/**

40

* Sets the DRM mode and offline license key set ID.

41

*

42

* @param mode The DRM mode

43

* @param offlineLicenseKeySetId The offline license key set ID, or null

44

*/

45

void setMode(@C.CryptoMode int mode, @Nullable byte[] offlineLicenseKeySetId);

46

47

/**

48

* Sets the player using this DRM session manager.

49

*

50

* @param playbackLooper The playback looper

51

* @param playerId The player ID

52

*/

53

void setPlayer(@Nullable Looper playbackLooper, @Nullable PlayerId playerId);

54

}

55

```

56

57

## DefaultDrmSessionManager

58

59

The default implementation of DrmSessionManager supporting common DRM schemes.

60

61

```java { .api }

62

public final class DefaultDrmSessionManager implements DrmSessionManager {

63

/**

64

* Builder for DefaultDrmSessionManager.

65

*/

66

public static final class Builder {

67

/**

68

* Creates a builder.

69

*/

70

public Builder();

71

72

/**

73

* Sets the UUID of the DRM scheme.

74

*

75

* @param uuid The DRM scheme UUID

76

* @return This builder

77

*/

78

public Builder setUuidAndExoMediaDrmProvider(UUID uuid, ExoMediaDrmProvider exoMediaDrmProvider);

79

80

/**

81

* Sets whether to use multiple sessions.

82

*

83

* @param multiSession Whether to use multiple sessions

84

* @return This builder

85

*/

86

public Builder setMultiSession(boolean multiSession);

87

88

/**

89

* Sets whether to play clear samples without keys.

90

*

91

* @param playClearSamplesWithoutKeys Whether to play clear samples without keys

92

* @return This builder

93

*/

94

public Builder setPlayClearSamplesWithoutKeys(boolean playClearSamplesWithoutKeys);

95

96

/**

97

* Sets the session keepalive timeout.

98

*

99

* @param useDrmSessionsForClearContentTrackTypes The track types

100

* @return This builder

101

*/

102

public Builder setUseDrmSessionsForClearContent(int... useDrmSessionsForClearContentTrackTypes);

103

104

/**

105

* Sets the key request parameters.

106

*

107

* @param keyRequestParameters The key request parameters

108

* @return This builder

109

*/

110

public Builder setKeyRequestParameters(@Nullable Map<String, String> keyRequestParameters);

111

112

/**

113

* Sets the load error handling policy.

114

*

115

* @param loadErrorHandlingPolicy The load error handling policy

116

* @return This builder

117

*/

118

public Builder setLoadErrorHandlingPolicy(LoadErrorHandlingPolicy loadErrorHandlingPolicy);

119

120

/**

121

* Builds the DefaultDrmSessionManager.

122

*

123

* @param httpDataSource The HTTP data source for license requests

124

* @return The built DefaultDrmSessionManager

125

*/

126

public DefaultDrmSessionManager build(HttpDataSource.Factory httpDataSource);

127

}

128

129

/**

130

* Sets the mode and offline license key set ID.

131

*

132

* @param mode The DRM mode

133

* @param offlineLicenseKeySetId The offline license key set ID

134

*/

135

@Override

136

public void setMode(@C.CryptoMode int mode, @Nullable byte[] offlineLicenseKeySetId);

137

138

/**

139

* Sets the player.

140

*

141

* @param playbackLooper The playback looper

142

* @param playerId The player ID

143

*/

144

@Override

145

public void setPlayer(@Nullable Looper playbackLooper, @Nullable PlayerId playerId);

146

147

/**

148

* Prepares the DRM session manager.

149

*/

150

@Override

151

public void prepare();

152

153

/**

154

* Releases the DRM session manager.

155

*/

156

public void release();

157

}

158

```

159

160

## DrmSession Interface

161

162

Represents a DRM session that provides cryptographic keys for decryption.

163

164

```java { .api }

165

public interface DrmSession {

166

/**

167

* DRM session states.

168

*/

169

@IntDef({STATE_RELEASED, STATE_ERROR, STATE_OPENING, STATE_OPENED, STATE_OPENED_WITH_KEYS})

170

@interface State {}

171

172

int STATE_RELEASED = 0;

173

int STATE_ERROR = 1;

174

int STATE_OPENING = 2;

175

int STATE_OPENED = 3;

176

int STATE_OPENED_WITH_KEYS = 4;

177

178

/**

179

* Returns the current state of the session.

180

*

181

* @return The session state

182

*/

183

@State int getState();

184

185

/**

186

* Returns whether clear samples can be played.

187

*

188

* @return Whether clear samples can be played

189

*/

190

boolean playClearSamples();

191

192

/**

193

* Returns the session error, if any.

194

*

195

* @return The error, or null if none

196

*/

197

@Nullable DrmSessionException getError();

198

199

/**

200

* Returns the crypto configuration.

201

*

202

* @return The crypto configuration, or null if not available

203

*/

204

@Nullable CryptoConfig getCryptoConfig();

205

206

/**

207

* Returns whether secure decoding is required.

208

*

209

* @param mimeType The MIME type

210

* @return Whether secure decoding is required

211

*/

212

boolean requiresSecureDecoder(String mimeType);

213

214

/**

215

* Acquires a reference to this session.

216

*

217

* @param eventDispatcher The event dispatcher

218

* @return This session

219

*/

220

DrmSession acquire(@Nullable DrmSessionEventListener.EventDispatcher eventDispatcher);

221

222

/**

223

* Releases a reference to this session.

224

*

225

* @param eventDispatcher The event dispatcher

226

*/

227

void release(@Nullable DrmSessionEventListener.EventDispatcher eventDispatcher);

228

}

229

```

230

231

## DrmSessionEventListener

232

233

Listener for DRM session events.

234

235

```java { .api }

236

public interface DrmSessionEventListener {

237

/**

238

* Called when a DRM session manager error occurs.

239

*

240

* @param error The error

241

*/

242

default void onDrmSessionManagerError(Exception error) {}

243

244

/**

245

* Called when DRM keys are loaded.

246

*/

247

default void onDrmKeysLoaded() {}

248

249

/**

250

* Called when a DRM session is acquired.

251

*/

252

default void onDrmSessionAcquired() {}

253

254

/**

255

* Called when DRM keys are removed.

256

*/

257

default void onDrmKeysRemoved() {}

258

259

/**

260

* Called when DRM keys are restored.

261

*/

262

default void onDrmKeysRestored() {}

263

264

/**

265

* Called when a DRM session is released.

266

*/

267

default void onDrmSessionReleased() {}

268

269

/**

270

* Event dispatcher for DRM session events.

271

*/

272

final class EventDispatcher {

273

/**

274

* Creates an event dispatcher.

275

*

276

* @param eventHandler The event handler

277

* @param eventListener The event listener

278

*/

279

public EventDispatcher(@Nullable Handler eventHandler,

280

@Nullable DrmSessionEventListener eventListener);

281

282

/**

283

* Dispatches a DRM session manager error event.

284

*

285

* @param error The error

286

*/

287

public void drmSessionManagerError(Exception error);

288

289

/**

290

* Dispatches a DRM keys loaded event.

291

*/

292

public void drmKeysLoaded();

293

294

/**

295

* Dispatches a DRM session acquired event.

296

*/

297

public void drmSessionAcquired();

298

299

/**

300

* Dispatches a DRM keys removed event.

301

*/

302

public void drmKeysRemoved();

303

304

/**

305

* Dispatches a DRM keys restored event.

306

*/

307

public void drmKeysRestored();

308

309

/**

310

* Dispatches a DRM session released event.

311

*/

312

public void drmSessionReleased();

313

}

314

}

315

```

316

317

## MediaDrm and ExoMediaDrm

318

319

Interfaces for interacting with the Android MediaDrm system.

320

321

```java { .api }

322

public interface ExoMediaDrm {

323

/**

324

* Exception thrown by ExoMediaDrm operations.

325

*/

326

final class KeyRequest {

327

public final byte[] data;

328

public final String licenseServerUrl;

329

@KeyRequestType public final int requestType;

330

331

public KeyRequest(byte[] data, String licenseServerUrl, int requestType);

332

}

333

334

/**

335

* Exception thrown by ExoMediaDrm operations.

336

*/

337

final class ProvisionRequest {

338

public final byte[] data;

339

public final String defaultUrl;

340

341

public ProvisionRequest(byte[] data, String defaultUrl);

342

}

343

344

/**

345

* Sets the property value for the given property name.

346

*

347

* @param propertyName The property name

348

* @param value The property value

349

*/

350

void setPropertyString(String propertyName, String value);

351

352

/**

353

* Sets the property value for the given property name.

354

*

355

* @param propertyName The property name

356

* @param value The property value

357

*/

358

void setPropertyByteArray(String propertyName, byte[] value);

359

360

/**

361

* Gets the property value for the given property name.

362

*

363

* @param propertyName The property name

364

* @return The property value

365

*/

366

String getPropertyString(String propertyName);

367

368

/**

369

* Gets the property value for the given property name.

370

*

371

* @param propertyName The property name

372

* @return The property value

373

*/

374

byte[] getPropertyByteArray(String propertyName);

375

376

/**

377

* Opens a new DRM session.

378

*

379

* @return The session ID

380

* @throws MediaDrmException If opening the session fails

381

*/

382

byte[] openSession() throws MediaDrmException;

383

384

/**

385

* Closes a DRM session.

386

*

387

* @param sessionId The session ID

388

*/

389

void closeSession(byte[] sessionId);

390

391

/**

392

* Generates a key request.

393

*

394

* @param scope The scope (session ID or key set ID)

395

* @param init The initialization data

396

* @param mimeType The MIME type

397

* @param keyType The key type

398

* @param optionalParameters Optional parameters

399

* @return The key request

400

* @throws MediaDrmException If generating the request fails

401

*/

402

KeyRequest generateKeyRequest(byte[] scope, @Nullable byte[] init, @Nullable String mimeType,

403

@KeyType int keyType, @Nullable HashMap<String, String> optionalParameters)

404

throws MediaDrmException;

405

406

/**

407

* Provides a key response to the DRM session.

408

*

409

* @param scope The scope (session ID or key set ID)

410

* @param response The key response

411

* @return The key set ID for offline keys, or null for streaming keys

412

* @throws MediaDrmException If providing the response fails

413

*/

414

@Nullable byte[] provideKeyResponse(byte[] scope, byte[] response) throws MediaDrmException;

415

}

416

```

417

418

## Usage Examples

419

420

### Basic Widevine DRM Setup

421

422

```java

423

import androidx.media3.exoplayer.drm.DefaultDrmSessionManager;

424

import androidx.media3.exoplayer.drm.FrameworkMediaDrm;

425

import androidx.media3.exoplayer.drm.HttpMediaDrmCallback;

426

import androidx.media3.datasource.DefaultHttpDataSource;

427

import androidx.media3.common.C;

428

import java.util.UUID;

429

430

// Widevine UUID

431

UUID WIDEVINE_UUID = new UUID(0xEDEF8BA979D64ACEL, 0xA3C827DCD51D21EDL);

432

433

// Create HTTP data source for license requests

434

DefaultHttpDataSource.Factory httpDataSourceFactory = new DefaultHttpDataSource.Factory()

435

.setUserAgent("MyApp/1.0");

436

437

// Create DRM callback for license server communication

438

String licenseUrl = "https://your-license-server.com/license";

439

HttpMediaDrmCallback drmCallback = new HttpMediaDrmCallback(licenseUrl, httpDataSourceFactory);

440

441

// Create DRM session manager

442

DefaultDrmSessionManager drmSessionManager = new DefaultDrmSessionManager.Builder()

443

.setUuidAndExoMediaDrmProvider(WIDEVINE_UUID, FrameworkMediaDrm.DEFAULT_PROVIDER)

444

.build(drmCallback);

445

446

// Use with media source

447

MediaSource mediaSource = new DashMediaSource.Factory(dataSourceFactory)

448

.setDrmSessionManagerProvider(unusedMediaItem -> drmSessionManager)

449

.createMediaSource(MediaItem.fromUri(manifestUri));

450

451

player.setMediaSource(mediaSource);

452

```

453

454

### Custom License Headers and Parameters

455

456

```java

457

// Create DRM callback with custom headers

458

HttpMediaDrmCallback drmCallback = new HttpMediaDrmCallback(licenseUrl, httpDataSourceFactory);

459

460

// Add custom headers

461

Map<String, String> licenseHeaders = new HashMap<>();

462

licenseHeaders.put("Authorization", "Bearer " + authToken);

463

licenseHeaders.put("Content-Type", "application/octet-stream");

464

drmCallback.setKeyRequestHeaders(licenseHeaders);

465

466

// Create DRM session manager with custom parameters

467

Map<String, String> keyRequestParameters = new HashMap<>();

468

keyRequestParameters.put("userId", "user123");

469

keyRequestParameters.put("deviceId", "device456");

470

471

DefaultDrmSessionManager drmSessionManager = new DefaultDrmSessionManager.Builder()

472

.setUuidAndExoMediaDrmProvider(WIDEVINE_UUID, FrameworkMediaDrm.DEFAULT_PROVIDER)

473

.setKeyRequestParameters(keyRequestParameters)

474

.build(drmCallback);

475

```

476

477

### Multi-Session DRM

478

479

```java

480

// Enable multi-session for different DRM keys per track

481

DefaultDrmSessionManager drmSessionManager = new DefaultDrmSessionManager.Builder()

482

.setUuidAndExoMediaDrmProvider(WIDEVINE_UUID, FrameworkMediaDrm.DEFAULT_PROVIDER)

483

.setMultiSession(true) // Enable multiple sessions

484

.build(drmCallback);

485

```

486

487

### Offline License Management

488

489

```java

490

public class OfflineLicenseHelper {

491

private final DefaultDrmSessionManager drmSessionManager;

492

private final MediaDrmCallback mediaDrmCallback;

493

494

public OfflineLicenseHelper(UUID drmSchemeUuid, ExoMediaDrm.Provider mediaDrmProvider,

495

MediaDrmCallback mediaDrmCallback) {

496

this.mediaDrmCallback = mediaDrmCallback;

497

this.drmSessionManager = new DefaultDrmSessionManager.Builder()

498

.setUuidAndExoMediaDrmProvider(drmSchemeUuid, mediaDrmProvider)

499

.build(mediaDrmCallback);

500

}

501

502

/**

503

* Downloads an offline license.

504

*

505

* @param drmInitData The DRM initialization data

506

* @return The offline license key set ID

507

*/

508

public byte[] downloadLicense(DrmInitData drmInitData) throws DrmSessionException {

509

drmSessionManager.setMode(C.CRYPTO_MODE_AES_CTR, null);

510

drmSessionManager.prepare();

511

512

try {

513

DrmSession drmSession = drmSessionManager.acquireSession(Looper.myLooper(), drmInitData);

514

515

// Wait for keys to be loaded

516

while (drmSession.getState() == DrmSession.STATE_OPENING) {

517

try {

518

Thread.sleep(10);

519

} catch (InterruptedException e) {

520

Thread.currentThread().interrupt();

521

throw new DrmSessionException(e);

522

}

523

}

524

525

if (drmSession.getState() == DrmSession.STATE_ERROR) {

526

throw drmSession.getError();

527

}

528

529

// Get offline license key set ID

530

return getOfflineLicenseKeySetId(drmSession);

531

532

} finally {

533

drmSessionManager.release();

534

}

535

}

536

537

/**

538

* Renews an offline license.

539

*

540

* @param offlineLicenseKeySetId The offline license key set ID

541

* @return The renewed key set ID

542

*/

543

public byte[] renewLicense(byte[] offlineLicenseKeySetId) throws DrmSessionException {

544

drmSessionManager.setMode(C.CRYPTO_MODE_AES_CTR, offlineLicenseKeySetId);

545

drmSessionManager.prepare();

546

547

try {

548

// Renewal logic similar to download

549

return performLicenseRenewal(offlineLicenseKeySetId);

550

} finally {

551

drmSessionManager.release();

552

}

553

}

554

555

/**

556

* Releases an offline license.

557

*

558

* @param offlineLicenseKeySetId The offline license key set ID

559

*/

560

public void releaseLicense(byte[] offlineLicenseKeySetId) {

561

// Implementation to release offline license

562

}

563

564

private byte[] getOfflineLicenseKeySetId(DrmSession drmSession) {

565

// Extract key set ID from DRM session

566

return null; // Implementation specific

567

}

568

569

private byte[] performLicenseRenewal(byte[] keySetId) throws DrmSessionException {

570

// Implementation for license renewal

571

return keySetId;

572

}

573

}

574

```

575

576

### DRM Event Handling

577

578

```java

579

public class DrmEventHandler implements DrmSessionEventListener {

580

private static final String TAG = "DrmEventHandler";

581

582

@Override

583

public void onDrmSessionAcquired() {

584

Log.d(TAG, "DRM session acquired");

585

// Update UI to show DRM is ready

586

showDrmStatus("Protected content ready");

587

}

588

589

@Override

590

public void onDrmKeysLoaded() {

591

Log.d(TAG, "DRM keys loaded successfully");

592

// Start playback now that keys are available

593

startPlayback();

594

}

595

596

@Override

597

public void onDrmSessionManagerError(Exception error) {

598

Log.e(TAG, "DRM session manager error", error);

599

600

// Handle specific DRM errors

601

if (error instanceof UnsupportedDrmException) {

602

showError("DRM scheme not supported on this device");

603

} else if (error instanceof DrmSessionException) {

604

DrmSessionException drmError = (DrmSessionException) error;

605

handleDrmSessionError(drmError);

606

} else {

607

showError("DRM error: " + error.getMessage());

608

}

609

}

610

611

@Override

612

public void onDrmKeysRemoved() {

613

Log.d(TAG, "DRM keys removed");

614

// Handle key removal (e.g., license expired)

615

showError("License expired. Please renew.");

616

}

617

618

@Override

619

public void onDrmKeysRestored() {

620

Log.d(TAG, "DRM keys restored");

621

// Resume playback after key restoration

622

resumePlayback();

623

}

624

625

@Override

626

public void onDrmSessionReleased() {

627

Log.d(TAG, "DRM session released");

628

// Clean up DRM-related resources

629

cleanupDrmResources();

630

}

631

632

private void handleDrmSessionError(DrmSessionException error) {

633

// Handle specific DRM session errors

634

switch (error.reason) {

635

case DrmSessionException.ERROR_PROVISIONING_FAILED:

636

showError("Device provisioning failed");

637

break;

638

case DrmSessionException.ERROR_LICENSE_ACQUISITION_FAILED:

639

showError("Failed to acquire license");

640

break;

641

case DrmSessionException.ERROR_PROVISIONING_CONFIG_CHANGED:

642

showError("Provisioning configuration changed");

643

break;

644

default:

645

showError("DRM session error: " + error.getMessage());

646

}

647

}

648

649

private void showDrmStatus(String message) {

650

// Update UI with DRM status

651

}

652

653

private void showError(String message) {

654

// Display error to user

655

}

656

657

private void startPlaybook() {

658

// Start media playback

659

}

660

661

private void resumePlayback() {

662

// Resume media playback

663

}

664

665

private void cleanupDrmResources() {

666

// Clean up DRM-related resources

667

}

668

}

669

670

// Use the event handler

671

DrmEventHandler drmEventHandler = new DrmEventHandler();

672

DrmSessionEventListener.EventDispatcher eventDispatcher =

673

new DrmSessionEventListener.EventDispatcher(handler, drmEventHandler);

674

```

675

676

### ClearKey DRM (for testing)

677

678

```java

679

// ClearKey UUID (for testing purposes)

680

UUID CLEARKEY_UUID = new UUID(0x1077EFECC0B24D02L, 0xACE33C1E52E2FB4BL);

681

682

// Create ClearKey DRM session manager (no license server needed)

683

DefaultDrmSessionManager clearKeyDrmManager = new DefaultDrmSessionManager.Builder()

684

.setUuidAndExoMediaDrmProvider(CLEARKEY_UUID, FrameworkMediaDrm.DEFAULT_PROVIDER)

685

.build(new LocalMediaDrmCallback("{\"keys\":[{\"kty\":\"oct\",\"k\":\"base64-key\",\"kid\":\"base64-key-id\"}]}".getBytes()));

686

687

// Use for testing DRM functionality without a license server

688

```

689

690

### Custom DRM Configuration

691

692

```java

693

public class CustomDrmConfiguration {

694

695

public static DefaultDrmSessionManager createCustomDrmManager(Context context, String licenseUrl) {

696

// Create custom HTTP data source with timeout and retry configuration

697

DefaultHttpDataSource.Factory httpDataSourceFactory = new DefaultHttpDataSource.Factory()

698

.setUserAgent("MyApp/1.0")

699

.setConnectTimeoutMs(10000) // 10 second connect timeout

700

.setReadTimeoutMs(30000); // 30 second read timeout

701

702

// Create DRM callback with custom configuration

703

HttpMediaDrmCallback drmCallback = new HttpMediaDrmCallback(licenseUrl, httpDataSourceFactory);

704

705

// Set custom request properties

706

Map<String, String> requestProperties = new HashMap<>();

707

requestProperties.put("Custom-Header", "CustomValue");

708

drmCallback.setKeyRequestHeaders(requestProperties);

709

710

// Create load error handling policy for DRM requests

711

LoadErrorHandlingPolicy loadErrorHandlingPolicy = new DefaultLoadErrorHandlingPolicy() {

712

@Override

713

public long getRetryDelayMsFor(LoadErrorInfo loadErrorInfo) {

714

// Custom retry delay for DRM errors

715

return 2000; // 2 second delay between retries

716

}

717

718

@Override

719

public int getMinimumLoadableRetryCount(int dataType) {

720

// More retries for DRM requests

721

return dataType == C.DATA_TYPE_DRM ? 5 : super.getMinimumLoadableRetryCount(dataType);

722

}

723

};

724

725

return new DefaultDrmSessionManager.Builder()

726

.setUuidAndExoMediaDrmProvider(WIDEVINE_UUID, FrameworkMediaDrm.DEFAULT_PROVIDER)

727

.setLoadErrorHandlingPolicy(loadErrorHandlingPolicy)

728

.setPlayClearSamplesWithoutKeys(false) // Require keys for all samples

729

.setMultiSession(true) // Support multiple DRM sessions

730

.build(drmCallback);

731

}

732

}

733

```