Example #1
0
class AudibleDll(object):
    # relevant sizes
    ENCODED_BUFFER_MAX_SIZE = 0x400
    PCM_BUFFER_SIZE = 0x1000

    # known error codes
    ERROR_NO_NEXT_FRAME = -24

    def __init__(self, filepath=None):
        if filepath is None:
            parentDir = DEFAULT_DLL_DIRECTORY
            filename = DEFAULT_DLL_FILENAME
            filepath = os.path.join(parentDir, filename)

        if os.path.exists(filepath) is False:
            raise OSError('AAX Library does not exist at \'%s\'' % filepath)

        (self._parentDir, self._filename) = os.path.split(filepath)
        os.environ['PATH'] = ';'.join([os.environ['PATH'], self._parentDir])

        self._handle = CDLL(self._filename)

        self._loadDllFunctions()

    def _loadDllFunction(self, func_name, func_args):
        f = self._handle[func_name]
        f.argtypes = func_args[:]
        setattr(self._handle_funcs, func_name, f)

    def _loadDllFunctions(self):
        self._handle_funcs = UserDict()

        self._loadDllFunction('AAXOpenFileWinA',
                              [POINTER(POINTER(c_ubyte)),
                               POINTER(c_char)])

        self._loadDllFunction('AAXCloseFile', [POINTER(c_ubyte)])

        self._loadDllFunction('AAXAuthenticateWin', [POINTER(c_ubyte)])

        self._loadDllFunction(
            'AAXGetDRMType',
            [POINTER(c_ubyte), POINTER(c_int)])

        self._loadDllFunction('AAXSeek', [POINTER(c_ubyte), c_int])

        self._loadDllFunction('AAXSeekToChapter', [POINTER(c_ubyte), c_int])

        self._loadDllFunction(
            'AAXGetAudioChannelCount',
            [POINTER(c_ubyte), POINTER(wintypes.DWORD)])

        self._loadDllFunction(
            'AAXGetChapterCount',
            [POINTER(c_ubyte), POINTER(wintypes.DWORD)])

        self._loadDllFunction('AAXGetChapterInfo',
                              [POINTER(c_ubyte), c_uint,
                               POINTER(c_char)])

        self._loadDllFunction(
            'AAXGetChapterStartTime',
            [POINTER(c_ubyte), c_uint,
             POINTER(wintypes.DWORD)])

        self._loadDllFunction(
            'AAXGetSampleRate',
            [POINTER(c_ubyte), POINTER(wintypes.DWORD)])

        self._loadDllFunction('AAXGetEncodedAudio', [
            POINTER(c_ubyte),
            POINTER(c_char), wintypes.DWORD,
            POINTER(wintypes.DWORD)
        ])

        self._loadDllFunction(
            'AAXGetNextFrameInfo',
            [POINTER(c_ubyte), POINTER(c_char)])

        self._loadDllFunction('AAXDecodePCMFrame', [
            POINTER(c_ubyte),
            POINTER(c_char), wintypes.DWORD,
            POINTER(c_char), wintypes.DWORD,
            POINTER(wintypes.DWORD)
        ])

        self._loadDllFunction('AAXGetOriginalTitle', [
            POINTER(c_ubyte),
            POINTER(wintypes.DWORD),
            POINTER(wintypes.DWORD),
            POINTER(wintypes.DWORD),
            POINTER(wintypes.DWORD),
            POINTER(wintypes.DWORD),
            POINTER(wintypes.DWORD),
            POINTER(wintypes.DWORD),
            POINTER(wintypes.DWORD)
        ])

    def AAXGetOriginalTitle(self, aax_handle):
        a = wintypes.DWORD()
        b = wintypes.DWORD()
        c = wintypes.DWORD()
        d = wintypes.DWORD()
        e = wintypes.DWORD()
        f = wintypes.DWORD()
        g = wintypes.DWORD()
        h = wintypes.DWORD()

        returnCode = self._handle_funcs.AAXGetOriginalTitle(
            aax_handle, byref(a), byref(b), byref(c), byref(d), byref(e),
            byref(f), byref(g), byref(h))
        print returnCode
        print 'a:', a
        print 'b:', b
        print 'c:', c
        print 'd:', d
        print 'e:', e
        print 'f:', f
        print 'g:', g
        print 'h:', h

        from binascii import hexlify, unhexlify
        print hexlify(title_buf.raw)

    def AAXOpenFileWinA(self, file_path):
        _handle = (c_ubyte * 0x1000)()
        aax_handle = cast(_handle, POINTER(c_ubyte))
        fname_buf = create_string_buffer(file_path)

        returnCode = self._handle_funcs.AAXOpenFileWinA(
            byref(aax_handle), fname_buf)
        if returnCode != 0:
            raise DllReturnCodeError(returnCode)

        import struct
        print _handle
        #d = cast(_handle, c_char_p)
        print bytes(_handle).decode('ASCII')
        # for i in range(0, 0x1000, 0x10):
        # a, b, c, d = struct.unpack_from('<%02x%02x', d.value, offset=i)
        # print '%08x: %08x %08x %08x %08x' % (i, a, b, c, d)

        return aax_handle

    def AAXCloseFile(self, aax_handle):
        returnCode = self._handle_funcs.AAXCloseFile(aax_handle)
        if returnCode != 0:
            raise DllReturnCodeError(returnCode)

    def AAXAuthenticateWin(self, aax_handle):
        returnCode = self._handle_funcs.AAXAuthenticateWin(aax_handle)
        if returnCode != 0:
            raise DllReturnCodeError(returnCode)

    def AAXGetDRMType(self, aax_handle):
        drm_type = c_int()

        returnCode = self._handle_funcs.AAXGetDRMType(aax_handle,
                                                      byref(drm_type))
        if returnCode != 0:
            raise DllReturnCodeError(returnCode)
        return drm_type.value

    def AAXSeek(self, aax_handle, offset):
        offset = c_int(offset)
        returnCode = self._handle_funcs.AAXSeek(aax_handle, offset)
        if returnCode != 0:
            raise DllReturnCodeError(returnCode)

    def AAXSeekToChapter(self, aax_handle, chapter):
        chapter = c_int(chapter)
        returnCode = self._handle_funcs.AAXSeekToChapter(aax_handle, chapter)
        if returnCode != 0:
            raise DllReturnCodeError(returnCode)

    def AAXGetAudioChannelCount(self, aax_handle):
        channels = wintypes.DWORD()
        returnCode = self._handle_funcs.AAXGetAudioChannelCount(
            aax_handle, byref(channels))
        if returnCode != 0:
            raise DllReturnCodeError(returnCode)
        return channels.value

    def AAXGetChapterCount(self, aax_handle):
        chapters = wintypes.DWORD()
        returnCode = self._handle_funcs.AAXGetChapterCount(
            aax_handle, byref(chapters))
        if returnCode != 0:
            raise DllReturnCodeError(returnCode)
        return chapters.value

    def AAXGetChapterInfo(self, aax_handle, chapter):
        buf_size = 24
        buf = create_string_buffer(buf_size)
        # buf = cast(create_string_buffer(buf_size), POINTER(wintypes.BYTE))
        chapter = c_uint(chapter)

        returnCode = self._handle_funcs.AAXGetChapterInfo(
            aax_handle, chapter, buf)
        if returnCode != 0:
            raise DllReturnCodeError(returnCode)

        return ChapterInfo(buf.raw)

    def AAXGetChapterMetadata(self, aax_handle, chapter):
        buf_size = 22
        buf = create_string_buffer(buf_size)
        # buf = cast(create_string_buffer(buf_size), POINTER(wintypes.BYTE))
        chapter = c_uint(chapter)

        returnCode = self._handle_funcs.AAXGetChapterMetadata(
            aax_handle, chapter, buf)
        if returnCode != 0:
            raise DllReturnCodeError(returnCode)
        return buf

    def AAXGetChapterStartTime(self, aax_handle, chapter):
        chapter = c_uint(chapter)
        start_time = wintypes.DWORD()

        returnCode = self._handle_funcs.AAXGetChapterStartTime(
            aax_handle, chapter, byref(start_time))
        if returnCode != 0:
            raise DllReturnCodeError(returnCode)
        return start_time.value

    def AAXGetSampleRate(self, aax_handle):
        sample_rate = wintypes.DWORD()
        returnCode = self._handle_funcs.AAXGetSampleRate(
            aax_handle, byref(sample_rate))
        if returnCode != 0:
            raise DllReturnCodeError(returnCode)
        return sample_rate.value

    def AAXGetEncodedAudio(self, aax_handle):
        buf = create_string_buffer(AudibleDll.ENCODED_BUFFER_MAX_SIZE)
        length = wintypes.DWORD()

        returnCode = self._handle_funcs.AAXGetEncodedAudio(
            aax_handle, buf, AudibleDll.ENCODED_BUFFER_MAX_SIZE, byref(length))
        if returnCode != 0:
            raise DllReturnCodeError(returnCode)
        return (buf, length.value)

    def AAXDecodePCMFrame(self, aax_handle, buf, buf_size,
                          bytes_left_in_frame):
        buf_size = wintypes.DWORD(buf_size)
        bytes_left_in_frame = wintypes.DWORD(bytes_left_in_frame)
        decoded_buf = create_string_buffer(AudibleDll.PCM_BUFFER_SIZE)
        out_size = wintypes.DWORD()

        returnCode = self._handle_funcs.AAXDecodePCMFrame(
            aax_handle, buf, buf_size, decoded_buf, bytes_left_in_frame,
            byref(out_size))
        if returnCode != 0:
            raise DllReturnCodeError(returnCode)
        return (decoded_buf, out_size.value)

    def AAXGetNextFrameInfo(self, aax_handle):
        buf = create_string_buffer(len(FrameInfo()))
        returnCode = self._handle_funcs.AAXGetNextFrameInfo(aax_handle, buf)
        if returnCode != 0:
            if returnCode == AudibleDll.ERROR_NO_NEXT_FRAME:
                return None
            else:
                raise DllReturnCodeError(returnCode)
        return FrameInfo(buf.raw)