1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.drm; 18 19 import static android.drm.DrmConvertedStatus.STATUS_OK; 20 import static android.drm.DrmManagerClient.INVALID_SESSION; 21 22 import android.util.Log; 23 24 import java.io.FilterOutputStream; 25 import java.io.IOException; 26 import java.io.OutputStream; 27 import java.io.RandomAccessFile; 28 import java.net.UnknownServiceException; 29 import java.util.Arrays; 30 31 import libcore.io.Streams; 32 33 /** 34 * Stream that applies a {@link DrmManagerClient} transformation to data before 35 * writing to disk, similar to a {@link FilterOutputStream}. 36 * 37 * @hide 38 */ 39 public class DrmOutputStream extends OutputStream { 40 private static final String TAG = "DrmOutputStream"; 41 42 private final DrmManagerClient mClient; 43 private final RandomAccessFile mFile; 44 45 private int mSessionId = INVALID_SESSION; 46 47 /** 48 * @param file Opened with "rw" mode. 49 */ 50 public DrmOutputStream(DrmManagerClient client, RandomAccessFile file, String mimeType) 51 throws IOException { 52 mClient = client; 53 mFile = file; 54 55 mSessionId = mClient.openConvertSession(mimeType); 56 if (mSessionId == INVALID_SESSION) { 57 throw new UnknownServiceException("Failed to open DRM session for " + mimeType); 58 } 59 } 60 61 public void finish() throws IOException { 62 final DrmConvertedStatus status = mClient.closeConvertSession(mSessionId); 63 if (status.statusCode == STATUS_OK) { 64 mFile.seek(status.offset); 65 mFile.write(status.convertedData); 66 mSessionId = INVALID_SESSION; 67 } else { 68 throw new IOException("Unexpected DRM status: " + status.statusCode); 69 } 70 } 71 72 @Override 73 public void close() throws IOException { 74 if (mSessionId == INVALID_SESSION) { 75 Log.w(TAG, "Closing stream without finishing"); 76 } 77 78 mFile.close(); 79 } 80 81 @Override 82 public void write(byte[] buffer, int offset, int count) throws IOException { 83 Arrays.checkOffsetAndCount(buffer.length, offset, count); 84 85 final byte[] exactBuffer; 86 if (count == buffer.length) { 87 exactBuffer = buffer; 88 } else { 89 exactBuffer = new byte[count]; 90 System.arraycopy(buffer, offset, exactBuffer, 0, count); 91 } 92 93 final DrmConvertedStatus status = mClient.convertData(mSessionId, exactBuffer); 94 if (status.statusCode == STATUS_OK) { 95 mFile.write(status.convertedData); 96 } else { 97 throw new IOException("Unexpected DRM status: " + status.statusCode); 98 } 99 } 100 101 @Override 102 public void write(int oneByte) throws IOException { 103 Streams.writeSingleByte(this, oneByte); 104 } 105 } 106